Use ScopedFPDFAvail in EmbedderTest.

Avoid manual destruction. Add accessors, so most users can access
`avail_` without needing to know the underlying implementation. This
makes it easier to move `avail_` into the private section later.

Change-Id: Iff627a5f5bf064df9c672e63e2b45dcd322f8d90
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/86872
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp b/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp
index 90b131c..53669b4 100644
--- a/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp
+++ b/core/fpdfapi/edit/cpdf_creator_embeddertest.cpp
@@ -67,18 +67,18 @@
   FileAccessForTesting file_acc("linearized.pdf");
   FakeFileAccess fake_acc(&file_acc);
 
-  avail_ = FPDFAvail_Create(fake_acc.GetFileAvail(), fake_acc.GetFileAccess());
+  CreateAvail(fake_acc.GetFileAvail(), fake_acc.GetFileAccess());
   while (PDF_DATA_AVAIL !=
-         FPDFAvail_IsDocAvail(avail_, fake_acc.GetDownloadHints())) {
+         FPDFAvail_IsDocAvail(avail(), fake_acc.GetDownloadHints())) {
     fake_acc.SetRequestedDataAvailable();
   }
 
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // Load second page, to parse additional crossref sections.
   while (PDF_DATA_AVAIL !=
-         FPDFAvail_IsPageAvail(avail_, 1, fake_acc.GetDownloadHints())) {
+         FPDFAvail_IsPageAvail(avail(), 1, fake_acc.GetDownloadHints())) {
     fake_acc.SetRequestedDataAvailable();
   }
   // Simulate downloading of whole file.
diff --git a/fpdfsdk/fpdf_dataavail_embeddertest.cpp b/fpdfsdk/fpdf_dataavail_embeddertest.cpp
index bcd3ca3..3cae0c7 100644
--- a/fpdfsdk/fpdf_dataavail_embeddertest.cpp
+++ b/fpdfsdk/fpdf_dataavail_embeddertest.cpp
@@ -163,23 +163,23 @@
   // Document must load without crashing but is too malformed to be available.
   EXPECT_FALSE(OpenDocument("trailer_unterminated.pdf"));
   MockDownloadHints hints;
-  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints));
+  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail(), &hints));
 }
 
 TEST_F(FPDFDataAvailEmbedderTest, TrailerAsHexstring) {
   // Document must load without crashing but is too malformed to be available.
   EXPECT_FALSE(OpenDocument("trailer_as_hexstring.pdf"));
   MockDownloadHints hints;
-  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail_, &hints));
+  EXPECT_FALSE(FPDFAvail_IsDocAvail(avail(), &hints));
 }
 
 TEST_F(FPDFDataAvailEmbedderTest, LoadUsingHintTables) {
   TestAsyncLoader loader("feature_linearized_loading.pdf");
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  CreateAvail(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail(), loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 1, loader.hints()));
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail(), 1, loader.hints()));
 
   // No new data available, to prevent load "Pages" node.
   loader.set_is_new_data_available(false);
@@ -189,9 +189,9 @@
 
 TEST_F(FPDFDataAvailEmbedderTest, CheckFormAvailIfLinearized) {
   TestAsyncLoader loader("feature_linearized_loading.pdf");
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  CreateAvail(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail(), loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // Prevent access to non-requested data to coerce the parser to send new
@@ -202,7 +202,7 @@
   int status = PDF_FORM_NOTAVAIL;
   while (status == PDF_FORM_NOTAVAIL) {
     loader.FlushRequestedData();
-    status = FPDFAvail_IsFormAvail(avail_, loader.hints());
+    status = FPDFAvail_IsFormAvail(avail(), loader.hints());
   }
   EXPECT_NE(PDF_FORM_ERROR, status);
 }
@@ -210,9 +210,9 @@
 TEST_F(FPDFDataAvailEmbedderTest,
        DoNotLoadMainCrossRefForFirstPageIfLinearized) {
   TestAsyncLoader loader("feature_linearized_loading.pdf");
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  CreateAvail(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail(), loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
   const int first_page_num = FPDFAvail_GetFirstPageNum(document_);
 
@@ -224,7 +224,7 @@
   // Prevent access to non-requested data to coerce the parser to send new
   // request for non available (non-requested before) data.
   loader.set_is_new_data_available(false);
-  FPDFAvail_IsPageAvail(avail_, first_page_num, loader.hints());
+  FPDFAvail_IsPageAvail(avail(), first_page_num, loader.hints());
 
   // The main cross ref table should not be requested.
   // (It is always at file end)
@@ -233,7 +233,7 @@
   // Allow parse page.
   loader.set_is_new_data_available(true);
   ASSERT_EQ(PDF_DATA_AVAIL,
-            FPDFAvail_IsPageAvail(avail_, first_page_num, loader.hints()));
+            FPDFAvail_IsPageAvail(avail(), first_page_num, loader.hints()));
 
   // The main cross ref table should not be processed.
   // (It is always at file end)
@@ -248,9 +248,9 @@
 
 TEST_F(FPDFDataAvailEmbedderTest, LoadSecondPageIfLinearizedWithHints) {
   TestAsyncLoader loader("feature_linearized_loading.pdf");
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  CreateAvail(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail(), loader.hints()));
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   static constexpr uint32_t kSecondPageNum = 1;
@@ -263,7 +263,7 @@
   int status = PDF_DATA_NOTAVAIL;
   while (status == PDF_DATA_NOTAVAIL) {
     loader.FlushRequestedData();
-    status = FPDFAvail_IsPageAvail(avail_, kSecondPageNum, loader.hints());
+    status = FPDFAvail_IsPageAvail(avail(), kSecondPageNum, loader.hints());
   }
   EXPECT_EQ(PDF_DATA_AVAIL, status);
 
@@ -276,12 +276,12 @@
 TEST_F(FPDFDataAvailEmbedderTest, LoadInfoAfterReceivingWholeDocument) {
   TestAsyncLoader loader("linearized.pdf");
   loader.set_is_new_data_available(false);
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail_, loader.hints())) {
+  CreateAvail(loader.file_avail(), loader.file_access());
+  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail(), loader.hints())) {
     loader.FlushRequestedData();
   }
 
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // The "info" dictionary should still be unavailable.
@@ -290,7 +290,7 @@
   // Simulate receiving whole file.
   loader.set_is_new_data_available(true);
   // Load second page, to parse additional crossref sections.
-  EXPECT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 1, loader.hints()));
+  EXPECT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail(), 1, loader.hints()));
 
   EXPECT_TRUE(FPDF_GetMetaText(document_, "CreationDate", nullptr, 0));
 }
@@ -305,12 +305,12 @@
   memcpy(loader.file_contents() + *index, "/Info 29 0 R", 12);
 
   loader.set_is_new_data_available(false);
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail_, loader.hints())) {
+  CreateAvail(loader.file_avail(), loader.file_access());
+  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail(), loader.hints())) {
     loader.FlushRequestedData();
   }
 
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // The "Info" dictionary should be available for the linearized document, if
@@ -332,18 +332,18 @@
   memcpy(loader.file_contents() + *index, "/Info 99 0 R", 12);
 
   loader.set_is_new_data_available(false);
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail_, loader.hints())) {
+  CreateAvail(loader.file_avail(), loader.file_access());
+  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail(), loader.hints())) {
     loader.FlushRequestedData();
   }
 
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // Set all data available.
   loader.set_is_new_data_available(true);
   // Check second page, to load additional crossrefs.
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 0, loader.hints()));
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail(), 0, loader.hints()));
 
   // Test that api is robust enough to handle the bad case.
   EXPECT_FALSE(FPDF_GetMetaText(document_, "Type", nullptr, 0));
@@ -358,18 +358,18 @@
   memcpy(loader.file_contents() + *index, "/I_fo 27 0 R", 12);
 
   loader.set_is_new_data_available(false);
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail_, loader.hints())) {
+  CreateAvail(loader.file_avail(), loader.file_access());
+  while (PDF_DATA_AVAIL != FPDFAvail_IsDocAvail(avail(), loader.hints())) {
     loader.FlushRequestedData();
   }
 
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document_);
 
   // Set all data available.
   loader.set_is_new_data_available(true);
   // Check second page, to load additional crossrefs.
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail_, 0, loader.hints()));
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsPageAvail(avail(), 0, loader.hints()));
 
   // Test that api is robust enough to handle the bad case.
   EXPECT_FALSE(FPDF_GetMetaText(document_, "Type", nullptr, 0));
@@ -386,8 +386,8 @@
 
 TEST_F(FPDFDataAvailEmbedderTest, NegativePageIndex) {
   TestAsyncLoader loader("linearized.pdf");
-  avail_ = FPDFAvail_Create(loader.file_avail(), loader.file_access());
-  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail_, loader.hints()));
+  CreateAvail(loader.file_avail(), loader.file_access());
+  ASSERT_EQ(PDF_DATA_AVAIL, FPDFAvail_IsDocAvail(avail(), loader.hints()));
   EXPECT_EQ(PDF_DATA_NOTAVAIL,
-            FPDFAvail_IsPageAvail(avail_, -1, loader.hints()));
+            FPDFAvail_IsPageAvail(avail(), -1, loader.hints()));
 }
diff --git a/fpdfsdk/fpdf_view_embeddertest.cpp b/fpdfsdk/fpdf_view_embeddertest.cpp
index 35d0a60..2c369ec 100644
--- a/fpdfsdk/fpdf_view_embeddertest.cpp
+++ b/fpdfsdk/fpdf_view_embeddertest.cpp
@@ -794,7 +794,7 @@
   // loop either. See bug 875.
   int ret = PDF_DATA_NOTAVAIL;
   while (ret == PDF_DATA_NOTAVAIL)
-    ret = FPDFAvail_IsDocAvail(avail_, &hints);
+    ret = FPDFAvail_IsDocAvail(avail(), &hints);
   EXPECT_EQ(PDF_DATA_AVAIL, ret);
 }
 
@@ -1702,11 +1702,11 @@
   // Set up linearized PDF.
   FileAccessForTesting file_acc("linearized.pdf");
   FakeFileAccess fake_acc(&file_acc);
-  avail_ = FPDFAvail_Create(fake_acc.GetFileAvail(), fake_acc.GetFileAccess());
+  CreateAvail(fake_acc.GetFileAvail(), fake_acc.GetFileAccess());
   fake_acc.SetWholeFileAvailable();
 
   // Multiple trailers, \r line ending at the trailer ends (no \n).
-  document_ = FPDFAvail_GetDocument(avail_, nullptr);
+  document_ = FPDFAvail_GetDocument(avail(), nullptr);
   ASSERT_TRUE(document());
 
   // FPDF_GetTrailerEnds() positive testing.
diff --git a/testing/embedder_test.cpp b/testing/embedder_test.cpp
index d9c8b1b..1529fb1 100644
--- a/testing/embedder_test.cpp
+++ b/testing/embedder_test.cpp
@@ -76,8 +76,6 @@
   EXPECT_EQ(0U, saved_page_map_.size());
   if (document_)
     CloseDocument();
-
-  FPDFAvail_Destroy(avail_);
 }
 
 bool EmbedderTest::CreateEmptyDocument() {
@@ -147,31 +145,32 @@
                                       JavaScriptOption javascript_option,
                                       FakeFileAccess* network_simulator,
                                       FPDF_DOCUMENT* document,
-                                      FPDF_AVAIL* avail,
+                                      ScopedFPDFAvail* avail,
                                       FPDF_FORMHANDLE* form_handle) {
   network_simulator->AddSegment(0, 1024);
   network_simulator->SetRequestedDataAvailable();
-  *avail = FPDFAvail_Create(network_simulator->GetFileAvail(),
-                            network_simulator->GetFileAccess());
-  if (FPDFAvail_IsLinearized(*avail) == PDF_LINEARIZED) {
+  avail->reset(FPDFAvail_Create(network_simulator->GetFileAvail(),
+                                network_simulator->GetFileAccess()));
+  FPDF_AVAIL avail_ptr = avail->get();
+  if (FPDFAvail_IsLinearized(avail_ptr) == PDF_LINEARIZED) {
     int32_t nRet = PDF_DATA_NOTAVAIL;
     while (nRet == PDF_DATA_NOTAVAIL) {
       network_simulator->SetRequestedDataAvailable();
-      nRet =
-          FPDFAvail_IsDocAvail(*avail, network_simulator->GetDownloadHints());
+      nRet = FPDFAvail_IsDocAvail(avail_ptr,
+                                  network_simulator->GetDownloadHints());
     }
     if (nRet == PDF_DATA_ERROR)
       return false;
 
-    *document = FPDFAvail_GetDocument(*avail, password);
+    *document = FPDFAvail_GetDocument(avail_ptr, password);
     if (!*document)
       return false;
 
     nRet = PDF_DATA_NOTAVAIL;
     while (nRet == PDF_DATA_NOTAVAIL) {
       network_simulator->SetRequestedDataAvailable();
-      nRet =
-          FPDFAvail_IsFormAvail(*avail, network_simulator->GetDownloadHints());
+      nRet = FPDFAvail_IsFormAvail(avail_ptr,
+                                   network_simulator->GetDownloadHints());
     }
     if (nRet == PDF_FORM_ERROR)
       return false;
@@ -181,7 +180,7 @@
       nRet = PDF_DATA_NOTAVAIL;
       while (nRet == PDF_DATA_NOTAVAIL) {
         network_simulator->SetRequestedDataAvailable();
-        nRet = FPDFAvail_IsPageAvail(*avail, i,
+        nRet = FPDFAvail_IsPageAvail(avail_ptr, i,
                                      network_simulator->GetDownloadHints());
       }
       if (nRet == PDF_DATA_ERROR)
@@ -252,7 +251,7 @@
 
 int EmbedderTest::GetFirstPageNum() {
   int first_page = FPDFAvail_GetFirstPageNum(document_);
-  (void)FPDFAvail_IsPageAvail(avail_, first_page,
+  (void)FPDFAvail_IsPageAvail(avail(), first_page,
                               fake_file_access_->GetDownloadHints());
   return first_page;
 }
@@ -260,7 +259,7 @@
 int EmbedderTest::GetPageCount() {
   int page_count = FPDF_GetPageCount(document_);
   for (int i = 0; i < page_count; ++i)
-    (void)FPDFAvail_IsPageAvail(avail_, i,
+    (void)FPDFAvail_IsPageAvail(avail(), i,
                                 fake_file_access_->GetDownloadHints());
   return page_count;
 }
@@ -470,11 +469,10 @@
 
   FPDFDOC_ExitFormFillEnvironment(saved_form_handle_);
   FPDF_CloseDocument(saved_document_);
-  FPDFAvail_Destroy(saved_avail_);
+  saved_avail_.reset();
 
   saved_form_handle_ = nullptr;
   saved_document_ = nullptr;
-  saved_avail_ = nullptr;
 }
 
 FPDF_PAGE EmbedderTest::LoadSavedPage(int page_number) {
@@ -532,6 +530,11 @@
   fake_file_access_->SetWholeFileAvailable();
 }
 
+void EmbedderTest::CreateAvail(FX_FILEAVAIL* file_avail,
+                               FPDF_FILEACCESS* file) {
+  avail_.reset(FPDFAvail_Create(file_avail, file));
+}
+
 FPDF_PAGE EmbedderTest::Delegate::GetPage(FPDF_FORMFILLINFO* info,
                                           FPDF_DOCUMENT document,
                                           int page_index) {
diff --git a/testing/embedder_test.h b/testing/embedder_test.h
index 9869934..220bc0d 100644
--- a/testing/embedder_test.h
+++ b/testing/embedder_test.h
@@ -104,6 +104,10 @@
   FPDF_DOCUMENT document() const { return document_; }
   FPDF_FORMHANDLE form_handle() const { return form_handle_; }
 
+  // Wrapper for FPDFAvail_Create() to set `avail_`.
+  void CreateAvail(FX_FILEAVAIL* file_avail, FPDF_FILEACCESS* file);
+  FPDF_AVAIL avail() { return avail_.get(); }
+
   // Create an empty document, and its form fill environment. Returns true
   // on success or false on failure.
   bool CreateEmptyDocument();
@@ -211,7 +215,7 @@
                           JavaScriptOption javascript_option,
                           FakeFileAccess* network_simulator,
                           FPDF_DOCUMENT* document,
-                          FPDF_AVAIL* avail,
+                          ScopedFPDFAvail* avail,
                           FPDF_FORMHANDLE* form_handle);
 
   FPDF_FORMHANDLE SetupFormFillEnvironment(FPDF_DOCUMENT doc,
@@ -282,7 +286,7 @@
   FPDF_FORMHANDLE form_handle_ = nullptr;
   FPDF_FILEACCESS file_access_;                       // must outlive `avail_`.
   std::unique_ptr<FakeFileAccess> fake_file_access_;  // must outlive `avail_`.
-  FPDF_AVAIL avail_ = nullptr;
+  ScopedFPDFAvail avail_;
   PageNumberToHandleMap page_map_;
 
   FPDF_DOCUMENT saved_document_ = nullptr;
@@ -290,7 +294,7 @@
   FPDF_FILEACCESS saved_file_access_;  // must outlive `saved_avail_`.
   // must outlive `saved_avail_`.
   std::unique_ptr<FakeFileAccess> saved_fake_file_access_;
-  FPDF_AVAIL saved_avail_ = nullptr;
+  ScopedFPDFAvail saved_avail_;
   PageNumberToHandleMap saved_page_map_;
 
  private: