Remove CPDF_Stream ctor that takes a std::unique_ptr.

Switch callers to the constructor that takes a DataVector instead.

Bug: pdfium:1872
Change-Id: I228f7a33fc3b66d07e6a150690855f32eddba709
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/96194
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index 1d31cdb..8fe89ca 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -24,7 +24,7 @@
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_test_document.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/data_vector.h"
 #include "core/fxge/cfx_fillrenderoptions.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -404,15 +404,12 @@
 TEST_F(CPDF_PageContentGeneratorTest, ProcessFormWithPath) {
   auto pDoc = std::make_unique<CPDF_TestDocument>();
   pDoc->CreateNewDoc();
-  auto pDict = pdfium::MakeRetain<CPDF_Dictionary>();
-  const char content[] =
+  static constexpr uint8_t kContents[] =
       "q 1 0 0 1 0 0 cm 3.102 4.6700001 m 5.4500012 .28999999 "
       "l 4.2399998 3.1499999 4.65 2.98 3.456 0.24 c 3.102 4.6700001 l h f Q\n";
-  size_t buf_len = std::size(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, buf_len));
-  memcpy(buf.get(), content, buf_len);
-  auto pStream = pdfium::MakeRetain<CPDF_Stream>(std::move(buf), buf_len,
-                                                 std::move(pDict));
+  auto pStream = pdfium::MakeRetain<CPDF_Stream>(
+      DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+      pdfium::MakeRetain<CPDF_Dictionary>());
 
   // Create a form with a non-empty stream.
   auto pTestForm = std::make_unique<CPDF_Form>(pDoc.get(), nullptr, pStream);
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp
index 5f7283f..8d9b197 100644
--- a/core/fpdfapi/page/cpdf_image.cpp
+++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -26,6 +26,7 @@
 #include "core/fpdfapi/parser/cpdf_string.h"
 #include "core/fxcodec/jpeg/jpegmodule.h"
 #include "core/fxcrt/data_vector.h"
+#include "core/fxcrt/fx_memory.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxcrt/fx_stream.h"
 #include "core/fxcrt/span_util.h"
@@ -237,19 +238,18 @@
       pCS->AppendNew<CPDF_Name>("Indexed");
       pCS->AppendNew<CPDF_Name>("DeviceRGB");
       pCS->AppendNew<CPDF_Number>(static_cast<int>(palette_size - 1));
-      std::unique_ptr<uint8_t, FxFreeDeleter> pColorTable(
-          FX_Alloc2D(uint8_t, palette_size, 3));
-      uint8_t* ptr = pColorTable.get();
+      DataVector<uint8_t> color_table(Fx2DSizeOrDie(palette_size, 3));
+      auto color_table_span = pdfium::make_span(color_table);
       for (size_t i = 0; i < palette_size; i++) {
         uint32_t argb = pBitmap->GetPaletteArgb(i);
-        ptr[0] = FXARGB_R(argb);
-        ptr[1] = FXARGB_G(argb);
-        ptr[2] = FXARGB_B(argb);
-        ptr += 3;
+        color_table_span[0] = FXARGB_R(argb);
+        color_table_span[1] = FXARGB_G(argb);
+        color_table_span[2] = FXARGB_B(argb);
+        color_table_span = color_table_span.subspan(3);
       }
       auto pNewDict = m_pDocument->New<CPDF_Dictionary>();
-      auto pCTS = m_pDocument->NewIndirect<CPDF_Stream>(
-          std::move(pColorTable), palette_size * 3, std::move(pNewDict));
+      auto pCTS = m_pDocument->NewIndirect<CPDF_Stream>(std::move(color_table),
+                                                        std::move(pNewDict));
       pCS->AppendNew<CPDF_Reference>(m_pDocument.Get(), pCTS->GetObjNum());
       pDict->SetNewFor<CPDF_Reference>("ColorSpace", m_pDocument.Get(),
                                        pCS->GetObjNum());
@@ -270,25 +270,24 @@
     pMaskBitmap = pBitmap->CloneAlphaMask();
 
   if (pMaskBitmap) {
-    int32_t maskWidth = pMaskBitmap->GetWidth();
-    int32_t maskHeight = pMaskBitmap->GetHeight();
-    std::unique_ptr<uint8_t, FxFreeDeleter> mask_buf;
-    int32_t mask_size = 0;
+    const int32_t mask_width = pMaskBitmap->GetWidth();
+    const int32_t mask_height = pMaskBitmap->GetHeight();
+    DataVector<uint8_t> mask_buf;
     RetainPtr<CPDF_Dictionary> pMaskDict =
-        CreateXObjectImageDict(maskWidth, maskHeight);
+        CreateXObjectImageDict(mask_width, mask_height);
     pMaskDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
     pMaskDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
     if (pMaskBitmap->GetFormat() != FXDIB_Format::k1bppMask) {
-      mask_buf.reset(FX_AllocUninit2D(uint8_t, maskHeight, maskWidth));
-      mask_size = maskHeight * maskWidth;  // Safe since checked alloc returned.
-      for (int32_t a = 0; a < maskHeight; a++) {
-        memcpy(mask_buf.get() + a * maskWidth,
-               pMaskBitmap->GetScanline(a).data(), maskWidth);
+      mask_buf.resize(Fx2DSizeOrDie(mask_width, mask_height));
+      for (int32_t a = 0; a < mask_height; a++) {
+        memcpy(mask_buf.data() + a * mask_width,
+               pMaskBitmap->GetScanline(a).data(), mask_width);
       }
     }
-    pMaskDict->SetNewFor<CPDF_Number>("Length", mask_size);
+    pMaskDict->SetNewFor<CPDF_Number>(
+        "Length", pdfium::base::checked_cast<int>(mask_buf.size()));
     auto pNewStream = m_pDocument->NewIndirect<CPDF_Stream>(
-        std::move(mask_buf), mask_size, std::move(pMaskDict));
+        std::move(mask_buf), std::move(pMaskDict));
     pDict->SetNewFor<CPDF_Reference>("SMask", m_pDocument.Get(),
                                      pNewStream->GetObjNum());
   }
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index f928cfb..eadd4e8 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -26,6 +26,7 @@
 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
 #include "core/fxcodec/jpeg/jpegmodule.h"
 #include "core/fxcodec/scanlinedecoder.h"
+#include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxcrt/fx_safe_types.h"
@@ -175,13 +176,12 @@
     return nullptr;
 
   uint32_t dwOrigSize = size.ValueOrDie();
-  std::unique_ptr<uint8_t, FxFreeDeleter> pData;
+  DataVector<uint8_t> data;
   uint32_t dwStreamSize;
   if (decoder.IsEmpty()) {
     dwOrigSize = std::min<uint32_t>(dwOrigSize, m_pBuf.size() - m_Pos);
-    pData.reset(FX_AllocUninit(uint8_t, dwOrigSize));
-    auto dest_span = pdfium::make_span(pData.get(), dwOrigSize);
-    fxcrt::spancpy(dest_span, m_pBuf.subspan(m_Pos, dwOrigSize));
+    auto src_span = m_pBuf.subspan(m_Pos, dwOrigSize);
+    data = DataVector<uint8_t>(src_span.begin(), src_span.end());
     dwStreamSize = dwOrigSize;
     m_Pos += dwOrigSize;
   } else {
@@ -209,14 +209,12 @@
       dwStreamSize += m_Pos - dwPrevPos;
     }
     m_Pos = dwSavePos;
-    pData.reset(FX_AllocUninit(uint8_t, dwStreamSize));
-    auto dest_span = pdfium::make_span(pData.get(), dwStreamSize);
-    fxcrt::spancpy(dest_span, m_pBuf.subspan(m_Pos, dwStreamSize));
+    auto src_span = m_pBuf.subspan(m_Pos, dwStreamSize);
+    data = DataVector<uint8_t>(src_span.begin(), src_span.end());
     m_Pos += dwStreamSize;
   }
   pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(dwStreamSize));
-  return pdfium::MakeRetain<CPDF_Stream>(std::move(pData), dwStreamSize,
-                                         std::move(pDict));
+  return pdfium::MakeRetain<CPDF_Stream>(std::move(data), std::move(pDict));
 }
 
 CPDF_StreamParser::ElementType CPDF_StreamParser::ParseNextElement() {
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index a03a78c..16208c4 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -73,17 +73,14 @@
     m_DictObj->SetNewFor<CPDF_Boolean>("bool", false);
     m_DictObj->SetNewFor<CPDF_Number>("num", 0.23f);
     // Stream object.
-    const char content[] = "abcdefghijklmnopqrstuvwxyz";
-    size_t buf_len = std::size(content);
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(
-        FX_AllocUninit(uint8_t, buf_len));
-    memcpy(buf.get(), content, buf_len);
+    static constexpr char kContents[] = "abcdefghijklmnopqrstuvwxyz";
     auto pNewDict = pdfium::MakeRetain<CPDF_Dictionary>();
     m_StreamDictObj = pNewDict;
     m_StreamDictObj->SetNewFor<CPDF_String>("key1", L" test dict");
     m_StreamDictObj->SetNewFor<CPDF_Number>("key2", -1);
-    auto stream_obj = pdfium::MakeRetain<CPDF_Stream>(std::move(buf), buf_len,
-                                                      std::move(pNewDict));
+    auto stream_obj = pdfium::MakeRetain<CPDF_Stream>(
+        DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+        std::move(pNewDict));
     // Null Object.
     auto null_obj = pdfium::MakeRetain<CPDF_Null>();
     // All direct objects.
@@ -652,13 +649,10 @@
         int value = j + 200;
         vals[i]->SetNewFor<CPDF_Number>(key.c_str(), value);
       }
-      uint8_t content[] = "content: this is a stream";
-      size_t data_size = std::size(content);
-      std::unique_ptr<uint8_t, FxFreeDeleter> data(
-          FX_AllocUninit(uint8_t, data_size));
-      memcpy(data.get(), content, data_size);
-      stream_vals[i] =
-          arr->AppendNew<CPDF_Stream>(std::move(data), data_size, vals[i]);
+      static constexpr uint8_t kContents[] = "content: this is a stream";
+      stream_vals[i] = arr->AppendNew<CPDF_Stream>(
+          DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+          vals[i]);
     }
     for (size_t i = 0; i < 3; ++i) {
       TestArrayAccessors(arr.Get(), i,           // Array and index.
@@ -697,15 +691,12 @@
     auto stream_dict = pdfium::MakeRetain<CPDF_Dictionary>();
     stream_dict->SetNewFor<CPDF_String>("key1", "John", false);
     stream_dict->SetNewFor<CPDF_String>("key2", "King", false);
-    uint8_t data[] = "A stream for test";
+    static constexpr uint8_t kData[] = "A stream for test";
     // The data buffer will be owned by stream object, so it needs to be
     // dynamically allocated.
-    size_t buf_size = sizeof(data);
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(
-        FX_AllocUninit(uint8_t, buf_size));
-    memcpy(buf.get(), data, buf_size);
-    auto stream_val = arr->InsertNewAt<CPDF_Stream>(13, std::move(buf),
-                                                    buf_size, stream_dict);
+    CPDF_Stream* stream_val = arr->InsertNewAt<CPDF_Stream>(
+        13, DataVector<uint8_t>(std::begin(kData), std::end(kData)),
+        stream_dict);
     const char* const expected_str[] = {
         "true",          "false", "0",    "-1234", "2345", "0.05", "",
         "It is a test!", "NAME",  "test", "",      "",     "",     ""};
@@ -899,20 +890,16 @@
   static constexpr uint32_t kBufSize = 100;
   // The length field should be created on stream create.
   {
-    std::unique_ptr<uint8_t, FxFreeDeleter> data;
-    data.reset(FX_Alloc(uint8_t, kBufSize));
     auto stream = pdfium::MakeRetain<CPDF_Stream>(
-        std::move(data), kBufSize, pdfium::MakeRetain<CPDF_Dictionary>());
+        DataVector<uint8_t>(kBufSize), pdfium::MakeRetain<CPDF_Dictionary>());
     EXPECT_EQ(static_cast<int>(kBufSize),
               stream->GetDict()->GetIntegerFor(pdfium::stream::kLength));
   }
   // The length field should be corrected on stream create.
   {
-    std::unique_ptr<uint8_t, FxFreeDeleter> data;
-    data.reset(FX_Alloc(uint8_t, kBufSize));
     auto dict = pdfium::MakeRetain<CPDF_Dictionary>();
     dict->SetNewFor<CPDF_Number>(pdfium::stream::kLength, 30000);
-    auto stream = pdfium::MakeRetain<CPDF_Stream>(std::move(data), kBufSize,
+    auto stream = pdfium::MakeRetain<CPDF_Stream>(DataVector<uint8_t>(kBufSize),
                                                   std::move(dict));
     EXPECT_EQ(static_cast<int>(kBufSize),
               stream->GetDict()->GetIntegerFor(pdfium::stream::kLength));
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index dc3e811..231450d 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -54,15 +54,6 @@
       absl::get<DataVector<uint8_t>>(data_).size()));
 }
 
-CPDF_Stream::CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
-                         size_t size,
-                         RetainPtr<CPDF_Dictionary> pDict)
-    : data_(DataVector<uint8_t>(pData.get(), pData.get() + size)),
-      dict_(std::move(pDict)) {
-  SetLengthInDict(pdfium::base::checked_cast<int>(
-      absl::get<DataVector<uint8_t>>(data_).size()));
-}
-
 CPDF_Stream::~CPDF_Stream() {
   m_ObjNum = kInvalidObjNum;
   if (dict_ && dict_->GetObjNum() == kInvalidObjNum)
@@ -104,14 +95,13 @@
   auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pdfium::WrapRetain(this));
   pAcc->LoadAllDataRaw();
 
-  uint32_t streamSize = pAcc->GetSize();
   RetainPtr<const CPDF_Dictionary> pDict = GetDict();
   RetainPtr<CPDF_Dictionary> pNewDict;
   if (pDict && !pdfium::Contains(*pVisited, pDict.Get())) {
     pNewDict = ToDictionary(static_cast<const CPDF_Object*>(pDict.Get())
                                 ->CloneNonCyclic(bDirect, pVisited));
   }
-  return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(), streamSize,
+  return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(),
                                          std::move(pNewDict));
 }
 
diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h
index 2856729..1795a6e 100644
--- a/core/fpdfapi/parser/cpdf_stream.h
+++ b/core/fpdfapi/parser/cpdf_stream.h
@@ -14,7 +14,6 @@
 
 #include "core/fpdfapi/parser/cpdf_object.h"
 #include "core/fxcrt/data_vector.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxcrt/fx_string_wrappers.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
@@ -77,10 +76,6 @@
               RetainPtr<CPDF_Dictionary> pDict);
 
   CPDF_Stream(DataVector<uint8_t> pData, RetainPtr<CPDF_Dictionary> pDict);
-  // TODO(crbug.com/pdfium/1872): Replace with vector version above.
-  CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
-              size_t size,
-              RetainPtr<CPDF_Dictionary> pDict);
   ~CPDF_Stream() override;
 
   RetainPtr<CPDF_Object> CloneNonCyclic(
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp
index 96da9b1..7ee963f 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.cpp
+++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -13,20 +13,9 @@
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
+#include "core/fxcrt/data_vector.h"
 #include "third_party/base/check_op.h"
 
-CPDF_StreamAcc::OwnedData::OwnedData(
-    std::unique_ptr<uint8_t, FxFreeDeleter> buffer,
-    uint32_t size)
-    : buffer(std::move(buffer)), size(size) {}
-
-CPDF_StreamAcc::OwnedData::OwnedData(OwnedData&&) = default;
-
-CPDF_StreamAcc::OwnedData& CPDF_StreamAcc::OwnedData::operator=(OwnedData&&) =
-    default;
-
-CPDF_StreamAcc::OwnedData::~OwnedData() = default;
-
 CPDF_StreamAcc::CPDF_StreamAcc(RetainPtr<const CPDF_Stream> pStream)
     : m_pStream(std::move(pStream)) {}
 
@@ -81,7 +70,7 @@
 
 const uint8_t* CPDF_StreamAcc::GetData() const {
   if (is_owned())
-    return absl::get<OwnedData>(m_Data).buffer.get();
+    return absl::get<DataVector<uint8_t>>(m_Data).data();
   return (m_pStream && m_pStream->IsMemoryBased())
              ? m_pStream->GetInMemoryRawData().data()
              : nullptr;
@@ -89,7 +78,7 @@
 
 uint32_t CPDF_StreamAcc::GetSize() const {
   if (is_owned())
-    return absl::get<OwnedData>(m_Data).size;
+    return absl::get<DataVector<uint8_t>>(m_Data).size();
   return (m_pStream && m_pStream->IsMemoryBased()) ? m_pStream->GetRawSize()
                                                    : 0;
 }
@@ -108,17 +97,12 @@
   return ByteString(digest, 20);
 }
 
-std::unique_ptr<uint8_t, FxFreeDeleter> CPDF_StreamAcc::DetachData() {
-  if (is_owned()) {
-    auto& data = absl::get<OwnedData>(m_Data);
-    data.size = 0;
-    return std::move(data.buffer);
-  }
+DataVector<uint8_t> CPDF_StreamAcc::DetachData() {
+  if (is_owned())
+    return std::move(absl::get<DataVector<uint8_t>>(m_Data));
+
   auto span = absl::get<pdfium::span<const uint8_t>>(m_Data);
-  std::unique_ptr<uint8_t, FxFreeDeleter> result(
-      FX_AllocUninit(uint8_t, span.size()));
-  memcpy(result.get(), span.data(), span.size());
-  return result;
+  return DataVector<uint8_t>(span.begin(), span.end());
 }
 
 void CPDF_StreamAcc::ProcessRawData() {
@@ -134,11 +118,11 @@
     return;
   }
 
-  std::unique_ptr<uint8_t, FxFreeDeleter> pData = ReadRawStream();
-  if (!pData)
+  DataVector<uint8_t> data = ReadRawStream();
+  if (data.empty())
     return;
 
-  m_Data.emplace<OwnedData>(std::move(pData), dwSrcSize);
+  m_Data = std::move(data);
 }
 
 void CPDF_StreamAcc::ProcessFilteredData(uint32_t estimated_size,
@@ -150,18 +134,18 @@
   if (dwSrcSize == 0)
     return;
 
-  absl::variant<pdfium::span<const uint8_t>, OwnedData> src_data;
+  absl::variant<pdfium::span<const uint8_t>, DataVector<uint8_t>> src_data;
   pdfium::span<const uint8_t> src_span;
   if (m_pStream->IsMemoryBased()) {
     src_span = m_pStream->GetInMemoryRawData();
     src_data = src_span;
   } else {
-    std::unique_ptr<uint8_t, FxFreeDeleter> pTempSrcData = ReadRawStream();
-    if (!pTempSrcData)
+    DataVector<uint8_t> temp_src_data = ReadRawStream();
+    if (temp_src_data.empty())
       return;
 
-    src_span = pdfium::make_span(pTempSrcData.get(), dwSrcSize);
-    src_data.emplace<OwnedData>(std::move(pTempSrcData), dwSrcSize);
+    src_span = pdfium::make_span(temp_src_data);
+    src_data = std::move(temp_src_data);
   }
 
   std::unique_ptr<uint8_t, FxFreeDeleter> pDecodedData;
@@ -179,21 +163,21 @@
 
   if (pDecodedData) {
     DCHECK_NE(pDecodedData.get(), src_span.data());
-    m_Data.emplace<OwnedData>(std::move(pDecodedData), dwDecodedSize);
+    // TODO(crbug.com/pdfium/1872): Avoid copying.
+    m_Data = DataVector<uint8_t>(pDecodedData.get(),
+                                 pDecodedData.get() + dwDecodedSize);
   } else {
     m_Data = std::move(src_data);
   }
 }
 
-std::unique_ptr<uint8_t, FxFreeDeleter> CPDF_StreamAcc::ReadRawStream() const {
+DataVector<uint8_t> CPDF_StreamAcc::ReadRawStream() const {
   DCHECK(m_pStream);
   DCHECK(m_pStream->IsFileBased());
 
-  uint32_t dwSrcSize = m_pStream->GetRawSize();
-  DCHECK(dwSrcSize);
-  std::unique_ptr<uint8_t, FxFreeDeleter> pSrcData(
-      FX_Alloc(uint8_t, dwSrcSize));
-  if (!m_pStream->ReadRawData(0, pSrcData.get(), dwSrcSize))
-    return nullptr;
-  return pSrcData;
+  DataVector<uint8_t> result(m_pStream->GetRawSize());
+  DCHECK(!result.empty());
+  if (!m_pStream->ReadRawData(0, result.data(), result.size()))
+    return DataVector<uint8_t>();
+  return result;
 }
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.h b/core/fpdfapi/parser/cpdf_stream_acc.h
index 800adcf..22c1825 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.h
+++ b/core/fpdfapi/parser/cpdf_stream_acc.h
@@ -12,7 +12,7 @@
 #include <memory>
 
 #include "core/fxcrt/bytestring.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "third_party/abseil-cpp/absl/types/variant.h"
 #include "third_party/base/span.h"
@@ -40,22 +40,11 @@
   uint64_t KeyForCache() const;
   ByteString ComputeDigest() const;
   ByteString GetImageDecoder() const { return m_ImageDecoder; }
-  std::unique_ptr<uint8_t, FxFreeDeleter> DetachData();
+  DataVector<uint8_t> DetachData();
 
   int GetLength1ForTest() const;
 
  private:
-  // TODO(crbug.com/pdfium/1872): Replace with fxcrt::DataVector.
-  struct OwnedData {
-    OwnedData(std::unique_ptr<uint8_t, FxFreeDeleter> buffer, uint32_t size);
-    OwnedData(OwnedData&&);
-    OwnedData& operator=(OwnedData&&);
-    ~OwnedData();
-
-    std::unique_ptr<uint8_t, FxFreeDeleter> buffer;
-    uint32_t size;
-  };
-
   explicit CPDF_StreamAcc(RetainPtr<const CPDF_Stream> pStream);
   ~CPDF_StreamAcc() override;
 
@@ -64,8 +53,8 @@
   void ProcessFilteredData(uint32_t estimated_size, bool bImageAcc);
   const uint8_t* GetData() const;
 
-  // Reads the raw data from |m_pStream|, or return nullptr on failure.
-  std::unique_ptr<uint8_t, FxFreeDeleter> ReadRawStream() const;
+  // Returns the raw data from `m_pStream`, or no data on failure.
+  DataVector<uint8_t> ReadRawStream() const;
 
   bool is_owned() const { return m_Data.index() == 1; }
 
@@ -73,7 +62,7 @@
   RetainPtr<const CPDF_Dictionary> m_pImageParam;
   // Needs to outlive `m_Data` when the data is not owned.
   RetainPtr<const CPDF_Stream> const m_pStream;
-  absl::variant<pdfium::span<const uint8_t>, OwnedData> m_Data;
+  absl::variant<pdfium::span<const uint8_t>, DataVector<uint8_t>> m_Data;
 };
 
 #endif  // CORE_FPDFAPI_PARSER_CPDF_STREAM_ACC_H_
diff --git a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
index 4b774d9..08dd869 100644
--- a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
+++ b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
@@ -13,7 +13,7 @@
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/data_vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -86,12 +86,10 @@
   auto size_array = func_dict->SetNewFor<CPDF_Array>("Size");
   size_array->AppendNew<CPDF_Number>(4);
 
-  static const char content[] = "1234";
-  size_t len = std::size(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
-  memcpy(buf.get(), content, len);
-  return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
-                                         std::move(func_dict));
+  static constexpr uint8_t kContents[] = "1234";
+  return pdfium::MakeRetain<CPDF_Stream>(
+      DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+      std::move(func_dict));
 }
 
 RetainPtr<CPDF_Dictionary> CreateType2FunctionDict() {
@@ -128,12 +126,10 @@
   range_array->AppendNew<CPDF_Number>(-1);
   range_array->AppendNew<CPDF_Number>(1);
 
-  static const char content[] = "{ 360 mul sin 2 div }";
-  size_t len = std::size(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
-  memcpy(buf.get(), content, len);
-  return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
-                                         std::move(func_dict));
+  static constexpr uint8_t kContents[] = "{ 360 mul sin 2 div }";
+  return pdfium::MakeRetain<CPDF_Stream>(
+      DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+      std::move(func_dict));
 }
 
 RetainPtr<CPDF_Stream> CreateBadType4FunctionStream() {
@@ -148,12 +144,10 @@
   range_array->AppendNew<CPDF_Number>(-1);
   range_array->AppendNew<CPDF_Number>(1);
 
-  static const char content[] = "garbage";
-  size_t len = std::size(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
-  memcpy(buf.get(), content, len);
-  return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
-                                         std::move(func_dict));
+  static constexpr uint8_t kContents[] = "garbage";
+  return pdfium::MakeRetain<CPDF_Stream>(
+      DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
+      std::move(func_dict));
 }
 
 class TestDocRenderData : public CPDF_DocRenderData {
diff --git a/core/fpdfdoc/cpdf_filespec_unittest.cpp b/core/fpdfdoc/cpdf_filespec_unittest.cpp
index a51f87e..6c45d5f 100644
--- a/core/fpdfdoc/cpdf_filespec_unittest.cpp
+++ b/core/fpdfdoc/cpdf_filespec_unittest.cpp
@@ -14,7 +14,7 @@
 #include "core/fpdfapi/parser/cpdf_number.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/data_vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/test_support.h"
 
@@ -175,11 +175,9 @@
       // Set the file stream.
       auto pDict = pdfium::MakeRetain<CPDF_Dictionary>();
       size_t buf_len = strlen(streams[i]) + 1;
-      std::unique_ptr<uint8_t, FxFreeDeleter> buf(
-          FX_AllocUninit(uint8_t, buf_len));
-      memcpy(buf.get(), streams[i], buf_len);
-      file_dict->SetNewFor<CPDF_Stream>(keys[i], std::move(buf), buf_len,
-                                        std::move(pDict));
+      file_dict->SetNewFor<CPDF_Stream>(
+          keys[i], DataVector<uint8_t>(streams[i], streams[i] + buf_len),
+          std::move(pDict));
 
       // Check that the file content stream is as expected.
       EXPECT_STREQ(
@@ -212,10 +210,10 @@
     // Add a file stream to the embedded files dictionary.
     RetainPtr<CPDF_Dictionary> file_dict = dict_obj->GetMutableDictFor("EF");
     auto pDict = pdfium::MakeRetain<CPDF_Dictionary>();
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, 6));
-    memcpy(buf.get(), "hello", 6);
-    file_dict->SetNewFor<CPDF_Stream>("UF", std::move(buf), 6,
-                                      std::move(pDict));
+    static constexpr char kHello[] = "hello";
+    file_dict->SetNewFor<CPDF_Stream>(
+        "UF", DataVector<uint8_t>(std::begin(kHello), std::end(kHello)),
+        std::move(pDict));
 
     // Add a params dictionary to the file stream.
     RetainPtr<CPDF_Stream> stream = file_dict->GetMutableStreamFor("UF");
diff --git a/fpdfsdk/fpdf_attachment.cpp b/fpdfsdk/fpdf_attachment.cpp
index 4a8fe27..ace3458 100644
--- a/fpdfsdk/fpdf_attachment.cpp
+++ b/fpdfsdk/fpdf_attachment.cpp
@@ -23,6 +23,7 @@
 #include "core/fpdfdoc/cpdf_filespec.h"
 #include "core/fpdfdoc/cpdf_nametree.h"
 #include "core/fxcrt/cfx_datetime.h"
+#include "core/fxcrt/data_vector.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_memory_wrappers.h"
 #include "fpdfsdk/cpdfsdk_helpers.h"
@@ -244,10 +245,10 @@
       true);
 
   // Create the file stream and have the filespec dictionary link to it.
-  std::unique_ptr<uint8_t, FxFreeDeleter> stream(FX_AllocUninit(uint8_t, len));
-  memcpy(stream.get(), contents, len);
-  auto pFileStream = pDoc->NewIndirect<CPDF_Stream>(std::move(stream), len,
-                                                    std::move(pFileStreamDict));
+  const uint8_t* contents_as_bytes = static_cast<const uint8_t*>(contents);
+  auto pFileStream = pDoc->NewIndirect<CPDF_Stream>(
+      DataVector<uint8_t>(contents_as_bytes, contents_as_bytes + len),
+      std::move(pFileStreamDict));
   auto pEFDict = pFile->AsMutableDictionary()->SetNewFor<CPDF_Dictionary>("EF");
   pEFDict->SetNewFor<CPDF_Reference>("F", pDoc, pFileStream->GetObjNum());
   return true;