Introduce CFX_ReadOnlyByteStringStream.

Introduce a class that can take ownership of a ByteString and expose the
data as a read-only stream. Use this new class where possible. This
further simplifies object lifetime management in cxfa_node.cpp.

Change-Id: Ib7c9b709eebeacd90f6f5f5bd9043233d000960f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/96758
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
index f4603a2..2e90085 100644
--- a/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_hint_tables_unittest.cpp
@@ -16,7 +16,8 @@
 #include "core/fpdfapi/parser/cpdf_read_validator.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_syntax_parser.h"
-#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/bytestring.h"
+#include "core/fxcrt/cfx_read_only_string_stream.h"
 #include "core/fxcrt/fx_stream.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -47,9 +48,9 @@
       : CPDF_LinearizedHeader(pDict, szLastXRefOffset) {}
 
   static std::unique_ptr<CPDF_LinearizedHeader> MakeHeader(
-      const std::string& inline_data) {
-    CPDF_SyntaxParser parser(pdfium::MakeRetain<CFX_ReadOnlySpanStream>(
-        pdfium::as_bytes(pdfium::make_span(inline_data))));
+      ByteString inline_data) {
+    CPDF_SyntaxParser parser(
+        pdfium::MakeRetain<CFX_ReadOnlyStringStream>(std::move(inline_data)));
     RetainPtr<CPDF_Dictionary> dict =
         ToDictionary(parser.GetObjectBody(nullptr));
     DCHECK(dict);
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index aaa2353..f17adc3 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_string_stream.cpp",
+    "cfx_read_only_string_stream.h",
     "cfx_read_only_vector_stream.cpp",
     "cfx_read_only_vector_stream.h",
     "cfx_seekablestreamproxy.cpp",
diff --git a/core/fxcrt/cfx_read_only_string_stream.cpp b/core/fxcrt/cfx_read_only_string_stream.cpp
new file mode 100644
index 0000000..b596e6d
--- /dev/null
+++ b/core/fxcrt/cfx_read_only_string_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_string_stream.h"
+
+#include <utility>
+
+#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "third_party/base/span.h"
+
+CFX_ReadOnlyStringStream::CFX_ReadOnlyStringStream(ByteString data)
+    : data_(std::move(data)),
+      stream_(pdfium::MakeRetain<CFX_ReadOnlySpanStream>(data_.raw_span())) {}
+
+CFX_ReadOnlyStringStream::~CFX_ReadOnlyStringStream() = default;
+
+FX_FILESIZE CFX_ReadOnlyStringStream::GetSize() {
+  return stream_->GetSize();
+}
+
+bool CFX_ReadOnlyStringStream::ReadBlockAtOffset(void* buffer,
+                                                 FX_FILESIZE offset,
+                                                 size_t size) {
+  return stream_->ReadBlockAtOffset(buffer, offset, size);
+}
diff --git a/core/fxcrt/cfx_read_only_string_stream.h b/core/fxcrt/cfx_read_only_string_stream.h
new file mode 100644
index 0000000..e5738f9
--- /dev/null
+++ b/core/fxcrt/cfx_read_only_string_stream.h
@@ -0,0 +1,32 @@
+// 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_STRING_STREAM_H_
+#define CORE_FXCRT_CFX_READ_ONLY_STRING_STREAM_H_
+
+#include "core/fxcrt/bytestring.h"
+#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/retain_ptr.h"
+
+class CFX_ReadOnlySpanStream;
+
+class CFX_ReadOnlyStringStream 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_ReadOnlyStringStream(ByteString data);
+  ~CFX_ReadOnlyStringStream() override;
+
+  const ByteString data_;
+  const RetainPtr<CFX_ReadOnlySpanStream> stream_;
+};
+
+#endif  // CORE_FXCRT_CFX_READ_ONLY_STRING_STREAM_H_
diff --git a/fxjs/xfa/cjx_node.cpp b/fxjs/xfa/cjx_node.cpp
index 7c1bd8c..d5c4f65 100644
--- a/fxjs/xfa/cjx_node.cpp
+++ b/fxjs/xfa/cjx_node.cpp
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "core/fxcrt/cfx_memorystream.h"
-#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/cfx_read_only_string_stream.h"
 #include "core/fxcrt/fx_codepage.h"
 #include "core/fxcrt/xml/cfx_xmldocument.h"
 #include "core/fxcrt/xml/cfx_xmlelement.h"
@@ -219,7 +219,7 @@
     bOverwrite = runtime->ToBoolean(params[2]);
 
   auto stream =
-      pdfium::MakeRetain<CFX_ReadOnlySpanStream>(expression.raw_span());
+      pdfium::MakeRetain<CFX_ReadOnlyStringStream>(std::move(expression));
 
   CFX_XMLParser parser(stream);
   std::unique_ptr<CFX_XMLDocument> xml_doc = parser.Parse();
diff --git a/xfa/fxfa/parser/cxfa_node.cpp b/xfa/fxfa/parser/cxfa_node.cpp
index c190b1b..b5ef817 100644
--- a/xfa/fxfa/parser/cxfa_node.cpp
+++ b/xfa/fxfa/parser/cxfa_node.cpp
@@ -17,7 +17,7 @@
 #include <vector>
 
 #include "core/fxcrt/autorestorer.h"
-#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/cfx_read_only_string_stream.h"
 #include "core/fxcrt/cfx_read_only_vector_stream.h"
 #include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_codepage.h"
@@ -480,7 +480,6 @@
     return nullptr;
 
   FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
-  ByteString bsData;  // Must outlive |pImageFileRead|.
 
   RetainPtr<IFX_SeekableReadStream> pImageFileRead;
   if (wsImage.GetLength() > 0) {
@@ -492,9 +491,8 @@
             pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(buffer));
       }
     } else {
-      bsData = wsImage.ToDefANSI();
       pImageFileRead =
-          pdfium::MakeRetain<CFX_ReadOnlySpanStream>(bsData.raw_span());
+          pdfium::MakeRetain<CFX_ReadOnlyStringStream>(wsImage.ToDefANSI());
     }
   } else {
     WideString wsURL = wsHref;