Change PDFDataDecodeResult to use DataVector

Change PDFDataDecode() to return a struct that has a DataVector. Then
change RunLengthDecode(), A85Decode() and HexDecode() to return
DataVector as well. Now most temporary data copies are gone and
DataVector is being passed straight through the call stack.

Bug: pdfium:1872
Change-Id: I019c8425c438fed88b313a85d29a14ce61ca04d7
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/119323
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp
index 5fa511d..896f36e 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.cpp
+++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -153,16 +153,12 @@
   m_ImageDecoder = std::move(result.value().image_encoding);
   m_pImageParam = std::move(result.value().image_params);
 
-  if (!result.value().data) {
+  if (result.value().data.empty()) {
     m_Data = std::move(src_data);
     return;
   }
 
-  DCHECK_NE(result.value().data.get(), src_span.data());
-  // TODO(crbug.com/pdfium/1872): Avoid copying.
-  m_Data = DataVector<uint8_t>(
-      result.value().data.get(),
-      UNSAFE_TODO(result.value().data.get() + result.value().size));
+  m_Data = std::move(result.value().data);
 }
 
 DataVector<uint8_t> CPDF_StreamAcc::ReadRawStream() const {
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp
index 38b9a1f..ea10bde 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -114,9 +114,9 @@
   return true;
 }
 
-DataAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span) {
   if (src_span.empty()) {
-    return {nullptr, 0u, 0u};
+    return {DataVector<uint8_t>(), 0u};
   }
 
   // Count legal characters and zeros.
@@ -134,7 +134,7 @@
   }
   // No content to decode.
   if (pos == 0) {
-    return {nullptr, 0u, 0u};
+    return {DataVector<uint8_t>(), 0u};
   }
 
   // Count the space needed to contain non-zero characters. The encoding ratio
@@ -144,13 +144,11 @@
   size *= 4;
   size += space_for_non_zeroes;
   if (!size.IsValid()) {
-    return {nullptr, 0u, FX_INVALID_OFFSET};
+    return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
   }
 
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
-      FX_Alloc(uint8_t, size.ValueOrDie()));
-  uint8_t* dest_buf_ptr = dest_buf.get();
-  uint32_t dest_size = 0;
+  DataVector<uint8_t> dest_buf(size.ValueOrDie());
+  pdfium::span<uint8_t> dest_span(dest_buf);
   size_t state = 0;
   uint32_t res = 0;
   pos = 0;
@@ -161,10 +159,10 @@
     }
 
     if (ch == 'z') {
-      UNSAFE_TODO(FXSYS_memset(dest_buf_ptr + dest_size, 0, 4));
+      fxcrt::spanset(dest_span.first(4), 0);
+      dest_span = dest_span.subspan(4);
       state = 0;
       res = 0;
-      dest_size += 4;
       continue;
     }
 
@@ -180,7 +178,8 @@
     }
 
     for (size_t i = 0; i < 4; ++i) {
-      UNSAFE_TODO(dest_buf_ptr[dest_size++] = GetA85Result(res, i));
+      dest_span.front() = GetA85Result(res, i);
+      dest_span = dest_span.subspan(1);
     }
     state = 0;
     res = 0;
@@ -191,18 +190,20 @@
       res = res * 85 + 84;
     }
     for (size_t i = 0; i < state - 1; ++i) {
-      UNSAFE_TODO(dest_buf_ptr[dest_size++] = GetA85Result(res, i));
+      dest_span.front() = GetA85Result(res, i);
+      dest_span = dest_span.subspan(1);
     }
   }
   if (pos < src_span.size() && src_span[pos] == '>') {
     ++pos;
   }
-  return {std::move(dest_buf), dest_size, pos};
+  dest_buf.resize(dest_buf.size() - dest_span.size());
+  return {std::move(dest_buf), pos};
 }
 
-DataAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span) {
   if (src_span.empty()) {
-    return {nullptr, 0u, 0u};
+    return {DataVector<uint8_t>(), 0u};
   }
 
   uint32_t i = 0;
@@ -211,11 +212,9 @@
     ++i;
   }
 
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
-      FX_Alloc(uint8_t, i / 2 + 1));
-  uint8_t* dest_buf_ptr = dest_buf.get();
-  uint32_t dest_size = 0;
-  bool bFirst = true;
+  DataVector<uint8_t> dest_buf(i / 2 + 1);
+  pdfium::span<uint8_t> dest_span(dest_buf);
+  bool is_first = true;
   for (i = 0; i < src_span.size(); ++i) {
     uint8_t ch = src_span[i];
     if (PDFCharIsLineEnding(ch) || ch == ' ' || ch == '\t') {
@@ -231,20 +230,24 @@
     }
 
     int digit = FXSYS_HexCharToInt(ch);
-    if (bFirst) {
-      UNSAFE_TODO(dest_buf_ptr[dest_size] = digit * 16);
+    if (is_first) {
+      dest_span.front() = digit * 16;
     } else {
-      UNSAFE_TODO(dest_buf_ptr[dest_size++] += digit);
+      dest_span.front() += digit;
+      dest_span = dest_span.subspan(1);
     }
-    bFirst = !bFirst;
+    is_first = !is_first;
   }
-  if (!bFirst) {
+  size_t dest_size = dest_buf.size() - dest_span.size();
+  if (!is_first) {
     ++dest_size;
   }
-  return {std::move(dest_buf), dest_size, i};
+  dest_buf.resize(dest_size);
+  return {std::move(dest_buf), i};
 }
 
-DataAndBytesConsumed RunLengthDecode(pdfium::span<const uint8_t> src_span) {
+DataVectorAndBytesConsumed RunLengthDecode(
+    pdfium::span<const uint8_t> src_span) {
   uint32_t dest_size = 0;
   size_t i = 0;
   while (i < src_span.size()) {
@@ -255,25 +258,23 @@
     if (src_span[i] < 128) {
       dest_size += src_span[i] + 1;
       if (dest_size < old) {
-        return {nullptr, 0, FX_INVALID_OFFSET};
+        return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
       }
       i += src_span[i] + 2;
     } else {
       dest_size += 257 - src_span[i];
       if (dest_size < old) {
-        return {nullptr, 0, FX_INVALID_OFFSET};
+        return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
       }
       i += 2;
     }
   }
   if (dest_size >= kMaxStreamSize) {
-    return {nullptr, 0, FX_INVALID_OFFSET};
+    return {DataVector<uint8_t>(), FX_INVALID_OFFSET};
   }
 
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
-      FX_Alloc(uint8_t, dest_size));
-  // SAFETY: allocation of `*dest_size` above.
-  auto dest_span = UNSAFE_BUFFERS(pdfium::make_span(dest_buf.get(), dest_size));
+  DataVector<uint8_t> dest_buf(dest_size);
+  auto dest_span = pdfium::make_span(dest_buf);
   i = 0;
   int dest_count = 0;
   while (i < src_span.size()) {
@@ -300,7 +301,7 @@
       i += 2;
     }
   }
-  return {std::move(dest_buf), dest_size,
+  return {std::move(dest_buf),
           pdfium::checked_cast<uint32_t>(std::min(i + 1, src_span.size()))};
 }
 
@@ -412,12 +413,10 @@
 PDFDataDecodeResult::PDFDataDecodeResult() = default;
 
 PDFDataDecodeResult::PDFDataDecodeResult(
-    std::unique_ptr<uint8_t, FxFreeDeleter> data,
-    uint32_t size,
+    DataVector<uint8_t> data,
     ByteString image_encoding,
     RetainPtr<const CPDF_Dictionary> image_params)
     : data(std::move(data)),
-      size(size),
       image_encoding(std::move(image_encoding)),
       image_params(std::move(image_params)) {}
 
@@ -444,55 +443,41 @@
     ByteString decoder = decoder_array[i].first;
     RetainPtr<const CPDF_Dictionary> pParam =
         ToDictionary(decoder_array[i].second);
-    std::unique_ptr<uint8_t, FxFreeDeleter> new_buf;
-    uint32_t new_size = 0xFFFFFFFF;
+    DataVector<uint8_t> new_buf;
     uint32_t bytes_consumed = FX_INVALID_OFFSET;
     if (decoder == "Crypt")
       continue;
     if (decoder == "FlateDecode" || decoder == "Fl") {
       if (bImageAcc && i == nSize - 1) {
-        result.size = last_span.size();
         result.image_encoding = "FlateDecode";
         result.image_params = std::move(pParam);
         return result;
       }
       DataVectorAndBytesConsumed decode_result = FlateOrLZWDecode(
           /*use_lzw=*/false, last_span, pParam, estimated_size);
-      // TODO(crbug.com/pdfium/1872): Avoid copying.
-      new_size = pdfium::checked_cast<uint32_t>(decode_result.data.size());
-      new_buf.reset(FX_Alloc(uint8_t, new_size));
-      UNSAFE_TODO(
-          FXSYS_memcpy(new_buf.get(), decode_result.data.data(), new_size));
+      new_buf = std::move(decode_result.data);
       bytes_consumed = decode_result.bytes_consumed;
     } else if (decoder == "LZWDecode" || decoder == "LZW") {
       DataVectorAndBytesConsumed decode_result =
           FlateOrLZWDecode(/*use_lzw=*/true, last_span, pParam, estimated_size);
-      // TODO(crbug.com/pdfium/1872): Avoid copying.
-      new_size = pdfium::checked_cast<uint32_t>(decode_result.data.size());
-      new_buf.reset(FX_Alloc(uint8_t, new_size));
-      UNSAFE_TODO(
-          FXSYS_memcpy(new_buf.get(), decode_result.data.data(), new_size));
+      new_buf = std::move(decode_result.data);
       bytes_consumed = decode_result.bytes_consumed;
     } else if (decoder == "ASCII85Decode" || decoder == "A85") {
-      DataAndBytesConsumed decode_result = A85Decode(last_span);
+      DataVectorAndBytesConsumed decode_result = A85Decode(last_span);
       new_buf = std::move(decode_result.data);
-      new_size = decode_result.size;
       bytes_consumed = decode_result.bytes_consumed;
     } else if (decoder == "ASCIIHexDecode" || decoder == "AHx") {
-      DataAndBytesConsumed decode_result = HexDecode(last_span);
+      DataVectorAndBytesConsumed decode_result = HexDecode(last_span);
       new_buf = std::move(decode_result.data);
-      new_size = decode_result.size;
       bytes_consumed = decode_result.bytes_consumed;
     } else if (decoder == "RunLengthDecode" || decoder == "RL") {
       if (bImageAcc && i == nSize - 1) {
-        result.size = last_span.size();
         result.image_encoding = "RunLengthDecode";
         result.image_params = std::move(pParam);
         return result;
       }
-      DataAndBytesConsumed decode_result = RunLengthDecode(last_span);
+      DataVectorAndBytesConsumed decode_result = RunLengthDecode(last_span);
       new_buf = std::move(decode_result.data);
-      new_size = decode_result.size;
       bytes_consumed = decode_result.bytes_consumed;
     } else {
       // If we get here, assume it's an image decoder.
@@ -501,7 +486,6 @@
       } else if (decoder == "CCF") {
         decoder = "CCITTFaxDecode";
       }
-      result.size = last_span.size();
       result.image_encoding = std::move(decoder);
       result.image_params = std::move(pParam);
       return result;
@@ -510,12 +494,10 @@
       return std::nullopt;
     }
 
-    // SAFETY: relies on out params of FlateOrLZWDecode().
-    last_span = UNSAFE_BUFFERS(pdfium::make_span(new_buf.get(), new_size));
+    last_span = pdfium::make_span(new_buf);
     result.data = std::move(new_buf);
   }
 
-  result.size = last_span.size();
   result.image_encoding.clear();
   result.image_params = nullptr;
   return result;
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.h b/core/fpdfapi/parser/fpdf_parser_decode.h
index d2552ad..27b628d 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.h
+++ b/core/fpdfapi/parser/fpdf_parser_decode.h
@@ -17,7 +17,6 @@
 
 #include "core/fxcodec/data_and_bytes_consumed.h"
 #include "core/fxcrt/data_vector.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/span.h"
@@ -54,12 +53,14 @@
     int bpc,
     const CPDF_Dictionary* pParams);
 
-fxcodec::DataAndBytesConsumed RunLengthDecode(
+fxcodec::DataVectorAndBytesConsumed RunLengthDecode(
     pdfium::span<const uint8_t> src_span);
 
-fxcodec::DataAndBytesConsumed A85Decode(pdfium::span<const uint8_t> src_span);
+fxcodec::DataVectorAndBytesConsumed A85Decode(
+    pdfium::span<const uint8_t> src_span);
 
-fxcodec::DataAndBytesConsumed HexDecode(pdfium::span<const uint8_t> src_span);
+fxcodec::DataVectorAndBytesConsumed HexDecode(
+    pdfium::span<const uint8_t> src_span);
 
 fxcodec::DataVectorAndBytesConsumed FlateOrLZWDecode(
     bool use_lzw,
@@ -79,17 +80,14 @@
 
 struct PDFDataDecodeResult {
   PDFDataDecodeResult();
-  PDFDataDecodeResult(std::unique_ptr<uint8_t, FxFreeDeleter> data,
-                      uint32_t size,
+  PDFDataDecodeResult(DataVector<uint8_t> data,
                       ByteString image_encoding,
                       RetainPtr<const CPDF_Dictionary> image_params);
   PDFDataDecodeResult(PDFDataDecodeResult&& that) noexcept;
   PDFDataDecodeResult& operator=(PDFDataDecodeResult&& that) noexcept;
   ~PDFDataDecodeResult();
 
-  // TODO(crbug.com/pdfium/1872): Convert to DataVector.
-  std::unique_ptr<uint8_t, FxFreeDeleter> data;
-  uint32_t size = 0;
+  DataVector<uint8_t> data;
   ByteString image_encoding;
   RetainPtr<const CPDF_Dictionary> image_params;
 };
diff --git a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
index 806f279..b4bf142 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode_unittest.cpp
@@ -288,13 +288,13 @@
       STR_IN_OUT_CASE("FCfN8FCfN8vw", "testtest", 11),
   };
   for (const auto& test_case : kTestData) {
-    DataAndBytesConsumed result = A85Decode(
+    DataVectorAndBytesConsumed result = A85Decode(
         UNSAFE_TODO(pdfium::make_span(test_case.input, test_case.input_size)));
     EXPECT_EQ(test_case.processed_size, result.bytes_consumed)
         << "for case " << test_case.input;
-    ASSERT_EQ(test_case.expected_size, result.size);
-    const uint8_t* result_ptr = result.data.get();
-    for (size_t j = 0; j < result.size; ++j) {
+    ASSERT_EQ(test_case.expected_size, result.data.size());
+    const uint8_t* result_ptr = result.data.data();
+    for (size_t j = 0; j < result.data.size(); ++j) {
       EXPECT_EQ(test_case.expected[j], result_ptr[j])
           << "for case " << test_case.input << " char " << j;
     }
@@ -321,13 +321,13 @@
       STR_IN_OUT_CASE("12AcED3c3456", "\x12\xac\xed\x3c\x34\x56", 12),
   };
   for (const auto& test_case : kTestData) {
-    DataAndBytesConsumed result = HexDecode(
+    DataVectorAndBytesConsumed result = HexDecode(
         UNSAFE_TODO(pdfium::make_span(test_case.input, test_case.input_size)));
     EXPECT_EQ(test_case.processed_size, result.bytes_consumed)
         << "for case " << test_case.input;
-    ASSERT_EQ(test_case.expected_size, result.size);
-    const uint8_t* result_ptr = result.data.get();
-    for (size_t j = 0; j < result.size; ++j) {
+    ASSERT_EQ(test_case.expected_size, result.data.size());
+    const uint8_t* result_ptr = result.data.data();
+    for (size_t j = 0; j < result.data.size(); ++j) {
       EXPECT_EQ(test_case.expected[j], result_ptr[j])
           << "for case " << test_case.input << " char " << j;
     }
diff --git a/core/fxcodec/basic/rle_unittest.cpp b/core/fxcodec/basic/rle_unittest.cpp
index 4f150b0..50251e2 100644
--- a/core/fxcodec/basic/rle_unittest.cpp
+++ b/core/fxcodec/basic/rle_unittest.cpp
@@ -39,10 +39,10 @@
     // Case 1: Match, match
     const uint8_t src_buf_1[] = {2, 2, 2, 2, 4, 4, 4, 4, 4, 4};
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_1);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_1), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_1), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -51,10 +51,10 @@
     // Case 2: Match, non-match
     const uint8_t src_buf_2[] = {2, 2, 2, 2, 1, 2, 3, 4, 5, 6};
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_2);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_2), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_2), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -63,10 +63,10 @@
     // Case 3: Non-match, match
     const uint8_t src_buf_3[] = {1, 2, 3, 4, 5, 3, 3, 3, 3, 3};
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_3);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_3), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_3), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -79,10 +79,10 @@
     // Case 1: Match, match
     const uint8_t src_buf_1[260] = {1};
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_1);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_1), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_1), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_1[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -93,10 +93,10 @@
     for (uint16_t i = 128; i < 260; i++)
       src_buf_2[i] = static_cast<uint8_t>(i - 125);
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_2);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_2), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_2), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_2[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -107,10 +107,10 @@
     for (uint8_t i = 0; i < 128; i++)
       src_buf_3[i] = i;
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_3);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_3), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_3), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_3[i], decoded_buf_span[i]) << " at " << i;
     }
   }
@@ -121,10 +121,10 @@
     for (uint16_t i = 0; i < 260; i++)
       src_buf_4[i] = static_cast<uint8_t>(i);
     DataVector<uint8_t> dest_buf = BasicModule::RunLengthEncode(src_buf_4);
-    DataAndBytesConsumed result = RunLengthDecode(dest_buf);
-    ASSERT_EQ(sizeof(src_buf_4), result.size);
-    auto decoded_buf_span = pdfium::make_span(result.data.get(), result.size);
-    for (uint32_t i = 0; i < result.size; i++) {
+    DataVectorAndBytesConsumed result = RunLengthDecode(dest_buf);
+    ASSERT_EQ(sizeof(src_buf_4), result.data.size());
+    auto decoded_buf_span = pdfium::make_span(result.data);
+    for (uint32_t i = 0; i < decoded_buf_span.size(); i++) {
       EXPECT_EQ(src_buf_4[i], decoded_buf_span[i]) << " at " << i;
     }
   }
diff --git a/fpdfsdk/fpdf_attachment.cpp b/fpdfsdk/fpdf_attachment.cpp
index 4136ad5..a47ba62 100644
--- a/fpdfsdk/fpdf_attachment.cpp
+++ b/fpdfsdk/fpdf_attachment.cpp
@@ -35,8 +35,8 @@
 constexpr char kChecksumKey[] = "CheckSum";
 
 ByteString CFXByteStringHexDecode(const ByteString& bsHex) {
-  DataAndBytesConsumed result = HexDecode(bsHex.unsigned_span());
-  return ByteString(result.data.get(), result.size);
+  DataVectorAndBytesConsumed result = HexDecode(bsHex.unsigned_span());
+  return ByteString(ByteStringView(result.data));
 }
 
 // TODO(tsepez): should be UNSAFE_BUFFER_USAGE.