Introduce CFX_ReadOnlyVectorStream.

Introduce a class that can take ownership of a DataVector<uint8_t> and
expose the data as a read-only stream. Use this new class where
possible. In cxfa_node.cpp, this make object lifetime management easier.

Change-Id: I4b6d4a4bab40465fc035e86bf3a14877241299cb
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/96757
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
index 3c01139..ad6c017 100644
--- a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/cfx_read_only_vector_stream.h"
 #include "core/fxcrt/data_vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/invalid_seekable_read_stream.h"
@@ -68,7 +69,8 @@
 
 TEST(ReadValidatorTest, UnavailableData) {
   DataVector<uint8_t> test_data(kTestDataSize);
-  auto file = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(test_data);
+  auto file =
+      pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data));
   MockFileAvail file_avail;
   auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail);
 
@@ -91,7 +93,8 @@
 
 TEST(ReadValidatorTest, UnavailableDataWithHints) {
   DataVector<uint8_t> test_data(kTestDataSize);
-  auto file = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(test_data);
+  auto file =
+      pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data));
   MockFileAvail file_avail;
   auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail);
 
@@ -146,7 +149,8 @@
 
 TEST(ReadValidatorTest, IntOverflow) {
   DataVector<uint8_t> test_data(kTestDataSize);
-  auto file = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(test_data);
+  auto file =
+      pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data));
   MockFileAvail file_avail;
   auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail);
 
@@ -244,7 +248,8 @@
 
 TEST(ReadValidatorTest, CheckDataRangeAndRequestIfUnavailable) {
   DataVector<uint8_t> test_data(kTestDataSize);
-  auto file = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(test_data);
+  auto file =
+      pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(test_data));
   MockFileAvail file_avail;
   auto validator = pdfium::MakeRetain<CPDF_ReadValidator>(file, &file_avail);
 
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index 24dadb4..aaa2353 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -27,6 +27,8 @@
     "cfx_read_only_memory_stream.h",
     "cfx_read_only_span_stream.cpp",
     "cfx_read_only_span_stream.h",
+    "cfx_read_only_vector_stream.cpp",
+    "cfx_read_only_vector_stream.h",
     "cfx_seekablestreamproxy.cpp",
     "cfx_seekablestreamproxy.h",
     "cfx_timer.cpp",
diff --git a/core/fxcrt/cfx_read_only_vector_stream.cpp b/core/fxcrt/cfx_read_only_vector_stream.cpp
new file mode 100644
index 0000000..0e6488b
--- /dev/null
+++ b/core/fxcrt/cfx_read_only_vector_stream.cpp
@@ -0,0 +1,26 @@
+// Copyright 2022 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fxcrt/cfx_read_only_vector_stream.h"
+
+#include <utility>
+
+#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "third_party/base/span.h"
+
+CFX_ReadOnlyVectorStream::CFX_ReadOnlyVectorStream(DataVector<uint8_t> data)
+    : data_(std::move(data)),
+      stream_(pdfium::MakeRetain<CFX_ReadOnlySpanStream>(data_)) {}
+
+CFX_ReadOnlyVectorStream::~CFX_ReadOnlyVectorStream() = default;
+
+FX_FILESIZE CFX_ReadOnlyVectorStream::GetSize() {
+  return stream_->GetSize();
+}
+
+bool CFX_ReadOnlyVectorStream::ReadBlockAtOffset(void* buffer,
+                                                 FX_FILESIZE offset,
+                                                 size_t size) {
+  return stream_->ReadBlockAtOffset(buffer, offset, size);
+}
diff --git a/core/fxcrt/cfx_read_only_vector_stream.h b/core/fxcrt/cfx_read_only_vector_stream.h
new file mode 100644
index 0000000..ac93dca
--- /dev/null
+++ b/core/fxcrt/cfx_read_only_vector_stream.h
@@ -0,0 +1,34 @@
+// Copyright 2022 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CORE_FXCRT_CFX_READ_ONLY_VECTOR_STREAM_H_
+#define CORE_FXCRT_CFX_READ_ONLY_VECTOR_STREAM_H_
+
+#include <stdint.h>
+
+#include "core/fxcrt/data_vector.h"
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/retain_ptr.h"
+
+class CFX_ReadOnlySpanStream;
+
+class CFX_ReadOnlyVectorStream final : public IFX_SeekableReadStream {
+ public:
+  CONSTRUCT_VIA_MAKE_RETAIN;
+
+  // IFX_SeekableReadStream:
+  FX_FILESIZE GetSize() override;
+  bool ReadBlockAtOffset(void* buffer,
+                         FX_FILESIZE offset,
+                         size_t size) override;
+
+ private:
+  explicit CFX_ReadOnlyVectorStream(DataVector<uint8_t> data);
+  ~CFX_ReadOnlyVectorStream() override;
+
+  const DataVector<uint8_t> data_;
+  const RetainPtr<CFX_ReadOnlySpanStream> stream_;
+};
+
+#endif  // CORE_FXCRT_CFX_READ_ONLY_VECTOR_STREAM_H_
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index 08bf3bf..c190b1b 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -18,6 +18,7 @@
 
 #include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/cfx_read_only_vector_stream.h"
 #include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/fx_extension.h"
@@ -481,17 +482,15 @@
   FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
   ByteString bsData;  // Must outlive |pImageFileRead|.
 
-  // Must outlive |pImageFileRead|.
-  DataVector<uint8_t> buffer;
-
   RetainPtr<IFX_SeekableReadStream> pImageFileRead;
   if (wsImage.GetLength() > 0) {
     XFA_AttributeValue iEncoding = pImage->GetTransferEncoding();
     if (iEncoding == XFA_AttributeValue::Base64) {
-      bsData = wsImage.ToUTF8();
-      buffer = XFA_Base64Decode(bsData);
-      if (!buffer.empty())
-        pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlySpanStream>(buffer);
+      DataVector<uint8_t> buffer = XFA_Base64Decode(wsImage.ToUTF8());
+      if (!buffer.empty()) {
+        pImageFileRead =
+            pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(buffer));
+      }
     } else {
       bsData = wsImage.ToDefANSI();
       pImageFileRead =