Fix infinite recursion in CPDF_DocPageData::GetColorSpace().

BUG=pdfium:497

Review-Url: https://codereview.chromium.org/2003873002
diff --git a/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp b/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp
index f872906..f0c5302 100644
--- a/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp
+++ b/core/fpdfapi/fpdf_page/fpdf_page_doc.cpp
@@ -19,6 +19,7 @@
 #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h"
 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h"
 #include "core/fpdfapi/include/cpdf_modulemgr.h"
+#include "third_party/base/stl_util.h"
 
 void CPDF_ModuleMgr::InitPageModule() {
   m_pPageModule.reset(new CPDF_PageModule);
@@ -222,17 +223,29 @@
 CPDF_ColorSpace* CPDF_DocPageData::GetColorSpace(
     CPDF_Object* pCSObj,
     const CPDF_Dictionary* pResources) {
+  std::set<CPDF_Object*> visited;
+  return GetColorSpaceImpl(pCSObj, pResources, &visited);
+}
+
+CPDF_ColorSpace* CPDF_DocPageData::GetColorSpaceImpl(
+    CPDF_Object* pCSObj,
+    const CPDF_Dictionary* pResources,
+    std::set<CPDF_Object*>* pVisited) {
   if (!pCSObj)
     return nullptr;
 
+  if (pdfium::ContainsKey(*pVisited, pCSObj))
+    return nullptr;
+
   if (pCSObj->IsName()) {
     CFX_ByteString name = pCSObj->GetString();
     CPDF_ColorSpace* pCS = CPDF_ColorSpace::ColorspaceFromName(name);
     if (!pCS && pResources) {
       CPDF_Dictionary* pList = pResources->GetDictBy("ColorSpace");
       if (pList) {
-        pCSObj = pList->GetDirectObjectBy(name);
-        return GetColorSpace(pCSObj, nullptr);
+        pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
+        return GetColorSpaceImpl(pList->GetDirectObjectBy(name), nullptr,
+                                 pVisited);
       }
     }
     if (!pCS || !pResources)
@@ -254,14 +267,22 @@
         pDefaultCS = pColorSpaces->GetDirectObjectBy("DefaultCMYK");
         break;
     }
-    return pDefaultCS ? GetColorSpace(pDefaultCS, nullptr) : pCS;
+    if (!pDefaultCS)
+      return pCS;
+
+    pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
+    return GetColorSpaceImpl(pDefaultCS, nullptr, pVisited);
   }
 
   CPDF_Array* pArray = pCSObj->AsArray();
   if (!pArray || pArray->GetCount() == 0)
     return nullptr;
-  if (pArray->GetCount() == 1)
-    return GetColorSpace(pArray->GetDirectObjectAt(0), pResources);
+
+  if (pArray->GetCount() == 1) {
+    pdfium::ScopedSetInsertion<CPDF_Object*> insertion(pVisited, pCSObj);
+    return GetColorSpaceImpl(pArray->GetDirectObjectAt(0), pResources,
+                             pVisited);
+  }
 
   CPDF_CountedColorSpace* csData = nullptr;
   auto it = m_ColorSpaceMap.find(pCSObj);
diff --git a/core/fpdfapi/fpdf_page/pageint.h b/core/fpdfapi/fpdf_page/pageint.h
index 64d106f..b884338 100644
--- a/core/fpdfapi/fpdf_page/pageint.h
+++ b/core/fpdfapi/fpdf_page/pageint.h
@@ -10,6 +10,7 @@
 #include <map>
 #include <memory>
 #include <unordered_map>
+#include <set>
 #include <vector>
 
 #include "core/fpdfapi/fpdf_page/cpdf_contentmark.h"
@@ -356,6 +357,10 @@
   using CPDF_ImageMap = std::map<uint32_t, CPDF_CountedImage*>;
   using CPDF_PatternMap = std::map<CPDF_Object*, CPDF_CountedPattern*>;
 
+  CPDF_ColorSpace* GetColorSpaceImpl(CPDF_Object* pCSObj,
+                                     const CPDF_Dictionary* pResources,
+                                     std::set<CPDF_Object*>* pVisited);
+
   CPDF_Document* const m_pPDFDoc;
   FX_BOOL m_bForceClear;
   std::map<CFX_ByteString, CPDF_Stream*> m_HashProfileMap;
diff --git a/core/fpdfapi/fpdf_parser/cpdf_document.cpp b/core/fpdfapi/fpdf_parser/cpdf_document.cpp
index 13d9737..79965a2 100644
--- a/core/fpdfapi/fpdf_parser/cpdf_document.cpp
+++ b/core/fpdfapi/fpdf_parser/cpdf_document.cpp
@@ -394,9 +394,10 @@
     } else {
       int nPages = pKid->GetIntegerBy("Count");
       if (nPagesToGo < nPages) {
-        if (pdfium::ContainsValue(*pVisited, pKid))
+        if (pdfium::ContainsKey(*pVisited, pKid))
           return -1;
-        pdfium::ScopedSetInsertion<CPDF_Dictionary*>(pVisited, pKid);
+
+        pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid);
         if (InsertDeletePDFPage(pDoc, pKid, nPagesToGo, pPage, bInsert,
                                 pVisited) < 0) {
           return -1;