Fixing metadata not read from linearized file.

This still won't work if the info dict is not on the first page
without first calling FPDFAvail_IsFormAvail or FPDFAvail_IsPageAvail,
as these are the methods that trigger parsing the rest of the data.

Bug: pdfium:664
Change-Id: I0b0193e415a1153dcfb8bfba0e0482da6b6ba53c
Reviewed-on: https://pdfium-review.googlesource.com/6610
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
Reviewed-by: Nicolás Peña <npm@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index 1fdd59e..9bfb16b 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -374,6 +374,10 @@
   if (!m_pRootDict)
     return;
 
+  LoadDocumentInfo();
+}
+
+void CPDF_Document::LoadDocumentInfo() {
   CPDF_Object* pInfoObj = GetOrParseIndirectObject(m_pParser->GetInfoObjNum());
   if (pInfoObj)
     m_pInfoDict = pInfoObj->GetDict();
diff --git a/core/fpdfapi/parser/cpdf_document.h b/core/fpdfapi/parser/cpdf_document.h
index 493c1ed..e6107e1 100644
--- a/core/fpdfapi/parser/cpdf_document.h
+++ b/core/fpdfapi/parser/cpdf_document.h
@@ -87,6 +87,7 @@
   void LoadDoc();
   void LoadLinearizedDoc(const CPDF_LinearizedHeader* pLinearizationParams);
   void LoadPages();
+  void LoadDocumentInfo();
 
   void CreateNewDoc();
   CPDF_Dictionary* CreateNewPage(int iPage);
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index 01c3b8c..b2bde8d 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -360,6 +360,9 @@
   if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount))
     return false;
 
+  if (m_pTrailer)
+    m_Trailers.push_back(std::move(m_pTrailer));
+
   m_pTrailer = LoadTrailerV4();
   if (!m_pTrailer)
     return false;
@@ -1084,7 +1087,18 @@
 uint32_t CPDF_Parser::GetInfoObjNum() {
   CPDF_Reference* pRef =
       ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Info") : nullptr);
-  return pRef ? pRef->GetRefObjNum() : 0;
+  if (pRef)
+    return pRef->GetRefObjNum();
+
+  // Search trailers array from latest to earliest revision, as we want the
+  // most recent Info object number.
+  // See PDF 1.7 spec, section 3.4.5 - Incremental Updates.
+  for (auto it = m_Trailers.rbegin(); it != m_Trailers.rend(); ++it) {
+    pRef = ToReference(it->get()->GetObjectFor("Info"));
+    if (pRef)
+      return pRef->GetRefObjNum();
+  }
+  return 0;
 }
 
 std::unique_ptr<CPDF_Object> CPDF_Parser::ParseIndirectObject(
@@ -1545,7 +1559,8 @@
 CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() {
   uint32_t dwSaveMetadataObjnum = m_pSyntax->m_MetadataObjnum;
   m_pSyntax->m_MetadataObjnum = 0;
-  m_pTrailer.reset();
+  if (m_pTrailer)
+    m_Trailers.push_back(std::move(m_pTrailer));
   m_pSyntax->SetPos(m_LastXRefOffset - m_pSyntax->m_HeaderOffset);
 
   uint8_t ch = 0;
diff --git a/fpdfsdk/fpdfdoc.cpp b/fpdfsdk/fpdfdoc.cpp
index 1c445e6..7be53a6 100644
--- a/fpdfsdk/fpdfdoc.cpp
+++ b/fpdfsdk/fpdfdoc.cpp
@@ -394,6 +394,7 @@
   CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
   if (!pDoc)
     return 0;
+  pDoc->LoadDocumentInfo();
   CPDF_Dictionary* pInfo = pDoc->GetInfo();
   if (!pInfo)
     return 0;
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index 86f6f89..14aa6c1 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -74,12 +74,14 @@
 struct Options {
   Options()
       : show_config(false),
+        show_metadata(false),
         send_events(false),
         pages(false),
         md5(false),
         output_format(OUTPUT_NONE) {}
 
   bool show_config;
+  bool show_metadata;
   bool send_events;
   bool pages;
   bool md5;
@@ -625,6 +627,8 @@
     const std::string& cur_arg = args[cur_idx];
     if (cur_arg == "--show-config") {
       options->show_config = true;
+    } else if (cur_arg == "--show-metadata") {
+      options->show_metadata = true;
     } else if (cur_arg == "--send-events") {
       options->send_events = true;
     } else if (cur_arg == "--ppm") {
@@ -1108,6 +1112,19 @@
 
   (void)FPDF_GetDocPermissions(doc.get());
 
+  if (options.show_metadata) {
+    const char* metaTags[] = {"Title",   "Author",   "Subject",      "Keywords",
+                              "Creator", "Producer", "CreationDate", "ModDate"};
+    for (const char* metaTag : metaTags) {
+      char metaBuffer[4096];
+      int len = FPDF_GetMetaText(doc.get(), metaTag, metaBuffer, 4096);
+      printf("%-12s = %ls (%d bytes)\n", metaTag,
+             GetPlatformWString(reinterpret_cast<unsigned short*>(metaBuffer))
+                 .c_str(),
+             len);
+    }
+  }
+
   std::unique_ptr<void, FPDFFormHandleDeleter> form(
       FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
   form_callbacks.form_handle = form.get();