Move some CPDF_Object usage from CXFA_FFDoc up into CPDFXFA_Context.

Ideally, CXFA_FFDoc wouldn't have to poke into CPDF_Object subclasses.
Here we can use the IFX_SeekableStream interface to get some separtion
between these layers.

Change-Id: I79c3be46dfdddee894930a4f035c4c1076e7b671
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/63951
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
index 7d75948..5f86a90 100644
--- a/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
+++ b/fpdfsdk/fpdfxfa/cpdfxfa_context.cpp
@@ -9,7 +9,10 @@
 #include <algorithm>
 #include <utility>
 
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_seekablemultistream.h"
 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
 #include "fpdfsdk/cpdfsdk_pageview.h"
 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
@@ -44,6 +47,36 @@
          type == JSPLATFORM_ALERT_ICON_ASTERISK;
 }
 
+RetainPtr<CPDF_SeekableMultiStream> CreateXFAMultiStream(
+    const CPDF_Document* pPDFDoc) {
+  const CPDF_Dictionary* pRoot = pPDFDoc->GetRoot();
+  if (!pRoot)
+    return nullptr;
+
+  const CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
+  if (!pAcroForm)
+    return nullptr;
+
+  const CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA");
+  if (!pElementXFA)
+    return nullptr;
+
+  std::vector<const CPDF_Stream*> xfaStreams;
+  if (pElementXFA->IsArray()) {
+    const CPDF_Array* pXFAArray = pElementXFA->AsArray();
+    for (size_t i = 0; i < pXFAArray->size() / 2; i++) {
+      if (const CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1))
+        xfaStreams.push_back(pStream);
+    }
+  } else if (pElementXFA->IsStream()) {
+    xfaStreams.push_back(pElementXFA->AsStream());
+  }
+  if (xfaStreams.empty())
+    return nullptr;
+
+  return pdfium::MakeRetain<CPDF_SeekableMultiStream>(xfaStreams);
+}
+
 }  // namespace
 
 CPDFXFA_Context::CPDFXFA_Context(CPDF_Document* pPDFDoc)
@@ -100,8 +133,15 @@
 bool CPDFXFA_Context::LoadXFADoc() {
   m_nLoadStatus = FXFA_LOADSTATUS_LOADING;
   m_XFAPageList.clear();
-  m_pXFADoc =
-      CXFA_FFDoc::CreateAndOpen(m_pXFAApp.get(), &m_DocEnv, m_pPDFDoc.Get());
+
+  auto stream = CreateXFAMultiStream(m_pPDFDoc.Get());
+  if (!stream) {
+    FXSYS_SetLastError(FPDF_ERR_XFALOAD);
+    return false;
+  }
+
+  m_pXFADoc = CXFA_FFDoc::CreateAndOpen(m_pXFAApp.get(), &m_DocEnv,
+                                        m_pPDFDoc.Get(), stream);
   if (!m_pXFADoc) {
     FXSYS_SetLastError(FPDF_ERR_XFALOAD);
     return false;
diff --git a/xfa/fxfa/cxfa_ffdoc.cpp b/xfa/fxfa/cxfa_ffdoc.cpp
index 0196e5e..ac4b35f 100644
--- a/xfa/fxfa/cxfa_ffdoc.cpp
+++ b/xfa/fxfa/cxfa_ffdoc.cpp
@@ -10,10 +10,8 @@
 #include <memory>
 #include <vector>
 
-#include "core/fpdfapi/parser/cpdf_array.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_document.h"
-#include "core/fpdfapi/parser/cpdf_seekablemultistream.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fpdfdoc/cpdf_nametree.h"
@@ -56,27 +54,16 @@
 std::unique_ptr<CXFA_FFDoc> CXFA_FFDoc::CreateAndOpen(
     CXFA_FFApp* pApp,
     IXFA_DocEnvironment* pDocEnvironment,
-    CPDF_Document* pPDFDoc) {
+    CPDF_Document* pPDFDoc,
+    const RetainPtr<IFX_SeekableStream>& stream) {
   ASSERT(pApp);
   ASSERT(pDocEnvironment);
   ASSERT(pPDFDoc);
 
-  const CPDF_Dictionary* pRoot = pPDFDoc->GetRoot();
-  if (!pRoot)
-    return nullptr;
-
-  const CPDF_Dictionary* pAcroForm = pRoot->GetDictFor("AcroForm");
-  if (!pAcroForm)
-    return nullptr;
-
-  const CPDF_Object* pElementXFA = pAcroForm->GetDirectObjectFor("XFA");
-  if (!pElementXFA)
-    return nullptr;
-
   // Use WrapUnique() to keep constructor private.
   auto result =
       pdfium::WrapUnique(new CXFA_FFDoc(pApp, pDocEnvironment, pPDFDoc));
-  if (!result->OpenDoc(pElementXFA))
+  if (!result->OpenDoc(stream))
     return nullptr;
 
   return result;
@@ -109,22 +96,7 @@
   m_pApp->ClearEventTargets();
 }
 
-bool CXFA_FFDoc::ParseDoc(const CPDF_Object* pElementXFA) {
-  std::vector<const CPDF_Stream*> xfaStreams;
-  if (pElementXFA->IsArray()) {
-    const CPDF_Array* pXFAArray = pElementXFA->AsArray();
-    for (size_t i = 0; i < pXFAArray->size() / 2; i++) {
-      if (const CPDF_Stream* pStream = pXFAArray->GetStreamAt(i * 2 + 1))
-        xfaStreams.push_back(pStream);
-    }
-  } else if (pElementXFA->IsStream()) {
-    xfaStreams.push_back(pElementXFA->AsStream());
-  }
-  if (xfaStreams.empty())
-    return false;
-
-  auto stream = pdfium::MakeRetain<CPDF_SeekableMultiStream>(xfaStreams);
-
+bool CXFA_FFDoc::ParseDoc(const RetainPtr<IFX_SeekableStream>& stream) {
   CXFA_DocumentParser parser(m_pDocument.get());
   bool parsed = parser.Parse(stream, XFA_PacketType::Xdp);
 
@@ -156,8 +128,8 @@
   return m_DocView.get();
 }
 
-bool CXFA_FFDoc::OpenDoc(const CPDF_Object* pElementXFA) {
-  if (!ParseDoc(pElementXFA))
+bool CXFA_FFDoc::OpenDoc(const RetainPtr<IFX_SeekableStream>& stream) {
+  if (!ParseDoc(stream))
     return false;
 
   CFGAS_FontMgr* mgr = GetApp()->GetFDEFontMgr();
diff --git a/xfa/fxfa/cxfa_ffdoc.h b/xfa/fxfa/cxfa_ffdoc.h
index 06b1785..04d98bc 100644
--- a/xfa/fxfa/cxfa_ffdoc.h
+++ b/xfa/fxfa/cxfa_ffdoc.h
@@ -21,7 +21,6 @@
 class CFX_DIBitmap;
 class CFX_XMLDocument;
 class CPDF_Document;
-class CPDF_Object;
 class CXFA_FFApp;
 class CXFA_FFNotify;
 class CXFA_FFDocView;
@@ -45,7 +44,8 @@
   static std::unique_ptr<CXFA_FFDoc> CreateAndOpen(
       CXFA_FFApp* pApp,
       IXFA_DocEnvironment* pDocEnvironment,
-      CPDF_Document* pPDFDoc);
+      CPDF_Document* pPDFDoc,
+      const RetainPtr<IFX_SeekableStream>& stream);
 
   ~CXFA_FFDoc();
 
@@ -74,8 +74,8 @@
   CXFA_FFDoc(CXFA_FFApp* pApp,
              IXFA_DocEnvironment* pDocEnvironment,
              CPDF_Document* pPDFDoc);
-  bool OpenDoc(const CPDF_Object* pElementXFA);
-  bool ParseDoc(const CPDF_Object* pElementXFA);
+  bool OpenDoc(const RetainPtr<IFX_SeekableStream>& stream);
+  bool ParseDoc(const RetainPtr<IFX_SeekableStream>& stream);
 
   UnownedPtr<IXFA_DocEnvironment> const m_pDocEnvironment;
   UnownedPtr<CXFA_FFApp> const m_pApp;