Add additional dictionary locker methods.

Allow returning unretained references to the full complement of
objects from locked dictionaries.

-- re-write other dictionary methods in terms of new internal ones.
-- add tests for new cases.

Change-Id: Ie44fbf17ab5a1689e39e1e593d9456b6ce505273
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/97850
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp
index e03d286..8d274f7 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.cpp
+++ b/core/fpdfapi/parser/cpdf_dictionary.cpp
@@ -71,89 +71,91 @@
   return pCopy;
 }
 
-CPDF_Object* CPDF_Dictionary::GetMutableObjectForInternal(
-    const ByteString& key) {
-  auto it = m_Map.find(key);
-  return it != m_Map.end() ? it->second.Get() : nullptr;
-}
-
 const CPDF_Object* CPDF_Dictionary::GetObjectForInternal(
     const ByteString& key) const {
-  return const_cast<CPDF_Dictionary*>(this)->GetMutableObjectForInternal(key);
-}
-
-RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableObjectFor(
-    const ByteString& key) {
-  return pdfium::WrapRetain(GetMutableObjectForInternal(key));
+  auto it = m_Map.find(key);
+  return it != m_Map.end() ? it->second.Get() : nullptr;
 }
 
 const CPDF_Object* CPDF_Dictionary::GetObjectFor(const ByteString& key) const {
   return GetObjectForInternal(key);
 }
 
+RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableObjectFor(
+    const ByteString& key) {
+  return pdfium::WrapRetain(
+      const_cast<CPDF_Object*>(GetObjectForInternal(key)));
+}
+
+const CPDF_Object* CPDF_Dictionary::GetDirectObjectForInternal(
+    const ByteString& key) const {
+  const CPDF_Object* p = GetObjectForInternal(key);
+  return p ? const_cast<CPDF_Object*>(p)->GetMutableDirect().Get() : nullptr;
+}
+
 RetainPtr<const CPDF_Object> CPDF_Dictionary::GetDirectObjectFor(
     const ByteString& key) const {
-  return const_cast<CPDF_Dictionary*>(this)->GetMutableDirectObjectFor(key);
+  return pdfium::WrapRetain(GetDirectObjectForInternal(key));
 }
 
 RetainPtr<CPDF_Object> CPDF_Dictionary::GetMutableDirectObjectFor(
     const ByteString& key) {
-  RetainPtr<CPDF_Object> p = GetMutableObjectFor(key);
-  return p ? p->GetMutableDirect() : nullptr;
+  return pdfium::WrapRetain(
+      const_cast<CPDF_Object*>(GetDirectObjectForInternal(key)));
 }
 
 ByteString CPDF_Dictionary::GetStringFor(const ByteString& key) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return p ? p->GetString() : ByteString();
 }
 
 ByteString CPDF_Dictionary::GetStringFor(const ByteString& key,
                                          const ByteString& def) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return p ? p->GetString() : ByteString(def);
 }
 
 WideString CPDF_Dictionary::GetUnicodeTextFor(const ByteString& key) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   if (const CPDF_Reference* pRef = ToReference(p))
     p = pRef->GetDirect().Get();
   return p ? p->GetUnicodeText() : WideString();
 }
 
 ByteString CPDF_Dictionary::GetNameFor(const ByteString& key) const {
-  const CPDF_Name* p = ToName(GetObjectFor(key));
+  const CPDF_Name* p = ToName(GetObjectForInternal(key));
   return p ? p->GetString() : ByteString();
 }
 
 bool CPDF_Dictionary::GetBooleanFor(const ByteString& key,
                                     bool bDefault) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
 }
 
 int CPDF_Dictionary::GetIntegerFor(const ByteString& key) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return p ? p->GetInteger() : 0;
 }
 
 int CPDF_Dictionary::GetIntegerFor(const ByteString& key, int def) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return p ? p->GetInteger() : def;
 }
 
 int CPDF_Dictionary::GetDirectIntegerFor(const ByteString& key) const {
-  const CPDF_Number* p = ToNumber(GetObjectFor(key));
+  const CPDF_Number* p = ToNumber(GetObjectForInternal(key));
   return p ? p->GetInteger() : 0;
 }
 
 float CPDF_Dictionary::GetFloatFor(const ByteString& key) const {
-  const CPDF_Object* p = GetObjectFor(key);
+  const CPDF_Object* p = GetObjectForInternal(key);
   return p ? p->GetNumber() : 0;
 }
 
-const CPDF_Dictionary* CPDF_Dictionary::GetDictFor(
+const CPDF_Dictionary* CPDF_Dictionary::GetDictForInternal(
     const ByteString& key) const {
-  RetainPtr<const CPDF_Object> p = GetDirectObjectFor(key);
+  const CPDF_Object* p = GetDirectObjectForInternal(key);
   if (!p)
     return nullptr;
   if (const CPDF_Dictionary* pDict = p->AsDictionary())
@@ -163,9 +165,15 @@
   return nullptr;
 }
 
+const CPDF_Dictionary* CPDF_Dictionary::GetDictFor(
+    const ByteString& key) const {
+  return GetDictForInternal(key);
+}
+
 RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetMutableDictFor(
     const ByteString& key) {
-  return pdfium::WrapRetain(const_cast<CPDF_Dictionary*>(GetDictFor(key)));
+  return pdfium::WrapRetain(
+      const_cast<CPDF_Dictionary*>(GetDictForInternal(key)));
 }
 
 RetainPtr<CPDF_Dictionary> CPDF_Dictionary::GetOrCreateDictFor(
@@ -176,13 +184,18 @@
   return pdfium::WrapRetain(SetNewFor<CPDF_Dictionary>(key));
 }
 
+const CPDF_Array* CPDF_Dictionary::GetArrayForInternal(
+    const ByteString& key) const {
+  return ToArray(GetDirectObjectForInternal(key));
+}
+
 const CPDF_Array* CPDF_Dictionary::GetArrayFor(const ByteString& key) const {
-  return ToArray(GetDirectObjectFor(key).Get());
+  return GetArrayForInternal(key);
 }
 
 RetainPtr<CPDF_Array> CPDF_Dictionary::GetMutableArrayFor(
     const ByteString& key) {
-  return pdfium::WrapRetain(const_cast<CPDF_Array*>(GetArrayFor(key)));
+  return pdfium::WrapRetain(const_cast<CPDF_Array*>(GetArrayForInternal(key)));
 }
 
 RetainPtr<CPDF_Array> CPDF_Dictionary::GetOrCreateArrayFor(
@@ -193,19 +206,30 @@
   return pdfium::WrapRetain(SetNewFor<CPDF_Array>(key));
 }
 
+const CPDF_Stream* CPDF_Dictionary::GetStreamForInternal(
+    const ByteString& key) const {
+  return ToStream(GetDirectObjectForInternal(key));
+}
+
 RetainPtr<const CPDF_Stream> CPDF_Dictionary::GetStreamFor(
     const ByteString& key) const {
-  return ToStream(GetDirectObjectFor(key));
+  return pdfium::WrapRetain(GetStreamForInternal(key));
 }
 
 RetainPtr<CPDF_Stream> CPDF_Dictionary::GetMutableStreamFor(
     const ByteString& key) {
-  return ToStream(GetMutableDirectObjectFor(key));
+  return pdfium::WrapRetain(
+      const_cast<CPDF_Stream*>(GetStreamForInternal(key)));
+}
+
+const CPDF_Number* CPDF_Dictionary::GetNumberForInternal(
+    const ByteString& key) const {
+  return ToNumber(GetObjectForInternal(key));
 }
 
 RetainPtr<const CPDF_Number> CPDF_Dictionary::GetNumberFor(
     const ByteString& key) const {
-  return pdfium::WrapRetain(ToNumber(GetObjectFor(key)));
+  return pdfium::WrapRetain(GetNumberForInternal(key));
 }
 
 CFX_FloatRect CPDF_Dictionary::GetRectFor(const ByteString& key) const {
@@ -349,13 +373,3 @@
 CPDF_DictionaryLocker::~CPDF_DictionaryLocker() {
   m_pDictionary->m_LockCount--;
 }
-
-const CPDF_Array* CPDF_DictionaryLocker::GetArrayFor(
-    const ByteString& key) const {
-  return ToArray(GetObjectFor(key));
-}
-
-const CPDF_Dictionary* CPDF_DictionaryLocker::GetDictFor(
-    const ByteString& key) const {
-  return ToDictionary(GetObjectFor(key));
-}
diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h
index a712096..9cb6bb6 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.h
+++ b/core/fpdfapi/parser/cpdf_dictionary.h
@@ -130,7 +130,11 @@
 
   // No guarantees about result lifetime, use with caution.
   const CPDF_Object* GetObjectForInternal(const ByteString& key) const;
-  CPDF_Object* GetMutableObjectForInternal(const ByteString& key);
+  const CPDF_Object* GetDirectObjectForInternal(const ByteString& key) const;
+  const CPDF_Array* GetArrayForInternal(const ByteString& key) const;
+  const CPDF_Dictionary* GetDictForInternal(const ByteString& key) const;
+  const CPDF_Number* GetNumberForInternal(const ByteString& key) const;
+  const CPDF_Stream* GetStreamForInternal(const ByteString& key) const;
 
   ByteString MaybeIntern(const ByteString& str);
   RetainPtr<CPDF_Object> CloneNonCyclic(
@@ -162,12 +166,30 @@
 
   // Results are only valid for the lifetime of the Dictionary Locker.
   const CPDF_Dictionary* GetUnderlying() const { return m_pDictionary.Get(); }
-  const CPDF_Array* GetArrayFor(const ByteString& key) const;
-  const CPDF_Dictionary* GetDictFor(const ByteString& key) const;
   const CPDF_Object* GetObjectFor(const ByteString& key) const {
     CHECK(m_pDictionary->IsLocked());
     return m_pDictionary->GetObjectForInternal(key);
   }
+  const CPDF_Object* GetDirectObjectFor(const ByteString& key) const {
+    CHECK(m_pDictionary->IsLocked());
+    return m_pDictionary->GetDirectObjectForInternal(key);
+  }
+  const CPDF_Array* GetArrayFor(const ByteString& key) const {
+    CHECK(m_pDictionary->IsLocked());
+    return m_pDictionary->GetArrayForInternal(key);
+  }
+  const CPDF_Dictionary* GetDictFor(const ByteString& key) const {
+    CHECK(m_pDictionary->IsLocked());
+    return m_pDictionary->GetDictForInternal(key);
+  }
+  const CPDF_Number* GetNumberFor(const ByteString& key) const {
+    CHECK(m_pDictionary->IsLocked());
+    return m_pDictionary->GetNumberForInternal(key);
+  }
+  const CPDF_Stream* GetStreamFor(const ByteString& key) const {
+    CHECK(m_pDictionary->IsLocked());
+    return m_pDictionary->GetStreamForInternal(key);
+  }
 
  private:
   RetainPtr<const CPDF_Dictionary> const m_pDictionary;
diff --git a/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp b/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp
index dab1a61..462d5a0 100644
--- a/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_dictionary_unittest.cpp
@@ -7,18 +7,45 @@
 #include <utility>
 
 #include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(DictionaryTest, LockerGetters) {
   auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
-  dict->SetNewFor<CPDF_Dictionary>("A");
-  dict->SetNewFor<CPDF_Array>("B");
+  dict->SetNewFor<CPDF_Dictionary>("the-dictionary");
+  dict->SetNewFor<CPDF_Array>("the-array");
+  dict->SetNewFor<CPDF_Stream>("the-stream");
+  dict->SetNewFor<CPDF_Number>("the-number", 42);
 
   CPDF_DictionaryLocker locked_dict(std::move(dict));
-  EXPECT_TRUE(locked_dict.GetObjectFor("A"));
-  EXPECT_FALSE(locked_dict.GetArrayFor("A"));
-  EXPECT_TRUE(locked_dict.GetDictFor("A"));
-  EXPECT_TRUE(locked_dict.GetObjectFor("B"));
-  EXPECT_TRUE(locked_dict.GetArrayFor("B"));
-  EXPECT_FALSE(locked_dict.GetDictFor("B"));
+  EXPECT_TRUE(locked_dict.GetObjectFor("the-dictionary"));
+  EXPECT_FALSE(locked_dict.GetArrayFor("the-dictionary"));
+  EXPECT_TRUE(locked_dict.GetDictFor("the-dictionary"));
+  EXPECT_FALSE(locked_dict.GetStreamFor("the-dictionary"));
+  EXPECT_FALSE(locked_dict.GetNumberFor("the-dictionary"));
+
+  EXPECT_TRUE(locked_dict.GetObjectFor("the-array"));
+  EXPECT_TRUE(locked_dict.GetArrayFor("the-array"));
+  EXPECT_FALSE(locked_dict.GetDictFor("the-array"));
+  EXPECT_FALSE(locked_dict.GetStreamFor("the-array"));
+  EXPECT_FALSE(locked_dict.GetNumberFor("the-array"));
+
+  EXPECT_TRUE(locked_dict.GetObjectFor("the-stream"));
+  EXPECT_FALSE(locked_dict.GetArrayFor("the-stream"));
+  EXPECT_FALSE(locked_dict.GetDictFor("the-stream"));
+  EXPECT_TRUE(locked_dict.GetStreamFor("the-stream"));
+  EXPECT_FALSE(locked_dict.GetNumberFor("the-stream"));
+
+  EXPECT_TRUE(locked_dict.GetObjectFor("the-number"));
+  EXPECT_FALSE(locked_dict.GetArrayFor("the-number"));
+  EXPECT_FALSE(locked_dict.GetDictFor("the-number"));
+  EXPECT_FALSE(locked_dict.GetStreamFor("the-number"));
+  EXPECT_TRUE(locked_dict.GetNumberFor("the-number"));
+
+  EXPECT_FALSE(locked_dict.GetObjectFor("nonesuch"));
+  EXPECT_FALSE(locked_dict.GetArrayFor("nonesuch"));
+  EXPECT_FALSE(locked_dict.GetDictFor("nonesuch"));
+  EXPECT_FALSE(locked_dict.GetStreamFor("nonesuch"));
+  EXPECT_FALSE(locked_dict.GetNumberFor("nonesuch"));
 }