Use more spans in fxcrt streams.

Safer than discrete length/size arguments since we can use span
methods to get some bounds checks automatically.

Change-Id: Icf23116521738d142ad7a2783a7ac82d525a267f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/100450
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp
index 0195010..a22b9f5 100644
--- a/core/fpdfapi/page/cpdf_image.cpp
+++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -145,13 +145,13 @@
 
   uint32_t dwEstimateSize = std::min(size, 8192U);
   DataVector<uint8_t> data(dwEstimateSize);
-  if (!pFile->ReadBlockAtOffset(data.data(), 0, dwEstimateSize))
+  if (!pFile->ReadBlockAtOffset(data, 0))
     return;
 
   RetainPtr<CPDF_Dictionary> pDict = InitJPEG(data);
   if (!pDict && size > dwEstimateSize) {
     data.resize(size);
-    if (pFile->ReadBlockAtOffset(data.data(), 0, size))
+    if (pFile->ReadBlockAtOffset(data, 0))
       pDict = InitJPEG(data);
   }
   if (!pDict)
@@ -166,7 +166,7 @@
     return;
 
   DataVector<uint8_t> data(size);
-  if (!pFile->ReadBlockAtOffset(data.data(), 0, size))
+  if (!pFile->ReadBlockAtOffset(data, 0))
     return;
 
   RetainPtr<CPDF_Dictionary> pDict = InitJPEG(data);
diff --git a/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp b/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp
index 6fec3fe..97eb3d6 100644
--- a/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_avail_unittest.cpp
@@ -25,7 +25,7 @@
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
 
-  void SimulateReadError() { ReadBlockAtOffset(nullptr, 0, 1); }
+  void SimulateReadError() { ReadBlockAtOffset({}, 0); }
 
  private:
   TestReadValidator()
diff --git a/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp b/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp
index 8073c4c..2486fed 100644
--- a/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_page_object_avail_unittest.cpp
@@ -25,7 +25,7 @@
  public:
   CONSTRUCT_VIA_MAKE_RETAIN;
 
-  void SimulateReadError() { ReadBlockAtOffset(nullptr, 0, 1); }
+  void SimulateReadError() { ReadBlockAtOffset({}, 0); }
 
  private:
   TestReadValidator()
diff --git a/core/fpdfapi/parser/cpdf_parser_unittest.cpp b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
index 52e2ee8..da68641 100644
--- a/core/fpdfapi/parser/cpdf_parser_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_parser_unittest.cpp
@@ -307,8 +307,8 @@
   ASSERT_TRUE(pFileAccess);
 
   std::vector<unsigned char> data(pFileAccess->GetSize() + kTestHeaderOffset);
-  ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(&data.front() + kTestHeaderOffset,
-                                             0, pFileAccess->GetSize()));
+  ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(
+      pdfium::make_span(data).subspan(kTestHeaderOffset), 0));
   CPDF_TestParser parser;
   parser.InitTestFromBufferWithOffset(data, kTestHeaderOffset);
 
@@ -328,11 +328,11 @@
   ASSERT_TRUE(pFileAccess);
 
   std::vector<unsigned char> data(pFileAccess->GetSize() + kTestHeaderOffset);
-  ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(&data.front() + kTestHeaderOffset,
-                                             0, pFileAccess->GetSize()));
+  ASSERT_TRUE(pFileAccess->ReadBlockAtOffset(
+      pdfium::make_span(data).subspan(kTestHeaderOffset), 0));
+
   CPDF_TestParser parser;
   parser.InitTestFromBufferWithOffset(data, kTestHeaderOffset);
-
   EXPECT_TRUE(parser.ParseLinearizedHeader());
 }
 
diff --git a/core/fpdfapi/parser/cpdf_read_validator.cpp b/core/fpdfapi/parser/cpdf_read_validator.cpp
index 2ffe2fc..b6fd872 100644
--- a/core/fpdfapi/parser/cpdf_read_validator.cpp
+++ b/core/fpdfapi/parser/cpdf_read_validator.cpp
@@ -54,29 +54,28 @@
   has_unavailable_data_ = false;
 }
 
-bool CPDF_ReadValidator::ReadBlockAtOffset(void* buffer,
-                                           FX_FILESIZE offset,
-                                           size_t size) {
+bool CPDF_ReadValidator::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                           FX_FILESIZE offset) {
   if (offset < 0) {
     NOTREACHED();
     return false;
   }
 
   FX_SAFE_FILESIZE end_offset = offset;
-  end_offset += size;
+  end_offset += buffer.size();
   if (!end_offset.IsValid() || end_offset.ValueOrDie() > file_size_)
     return false;
 
-  if (!IsDataRangeAvailable(offset, size)) {
-    ScheduleDownload(offset, size);
+  if (!IsDataRangeAvailable(offset, buffer.size())) {
+    ScheduleDownload(offset, buffer.size());
     return false;
   }
 
-  if (file_read_->ReadBlockAtOffset(buffer, offset, size))
+  if (file_read_->ReadBlockAtOffset(buffer, offset))
     return true;
 
   read_error_ = true;
-  ScheduleDownload(offset, size);
+  ScheduleDownload(offset, buffer.size());
   return false;
 }
 
diff --git a/core/fpdfapi/parser/cpdf_read_validator.h b/core/fpdfapi/parser/cpdf_read_validator.h
index 77c36c6..c866541 100644
--- a/core/fpdfapi/parser/cpdf_read_validator.h
+++ b/core/fpdfapi/parser/cpdf_read_validator.h
@@ -45,9 +45,8 @@
   bool CheckWholeFileAndRequestIfUnavailable();
 
   // IFX_SeekableReadStream overrides:
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
   FX_FILESIZE GetSize() override;
 
  protected:
diff --git a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
index 804d808..bb3006a 100644
--- a/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_read_validator_unittest.cpp
@@ -76,18 +76,13 @@
       pdfium::MakeRetain<CPDF_ReadValidator>(std::move(file), &file_avail);
 
   DataVector<uint8_t> read_buffer(100);
-  EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer.data(), 5000,
-                                            read_buffer.size()));
-
+  EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer, 5000));
   EXPECT_FALSE(validator->read_error());
   EXPECT_TRUE(validator->has_unavailable_data());
 
   validator->ResetErrors();
-
   file_avail.SetAvailableRange(5000, 5000 + read_buffer.size());
-
-  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000,
-                                           read_buffer.size()));
+  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000));
   EXPECT_FALSE(validator->read_error());
   EXPECT_FALSE(validator->has_unavailable_data());
 }
@@ -104,9 +99,7 @@
   validator->SetDownloadHints(&hints);
 
   DataVector<uint8_t> read_buffer(100);
-
-  EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer.data(), 5000,
-                                            read_buffer.size()));
+  EXPECT_FALSE(validator->ReadBlockAtOffset(read_buffer, 5000));
   EXPECT_FALSE(validator->read_error());
   EXPECT_TRUE(validator->has_unavailable_data());
 
@@ -117,8 +110,7 @@
   hints.Reset();
 
   validator->ResetErrors();
-  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000,
-                                           read_buffer.size()));
+  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000));
   // No new request on already available data.
   EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange());
   EXPECT_FALSE(validator->read_error());
@@ -127,8 +119,7 @@
   validator->ResetErrors();
   // Try read unavailable data at file end.
   EXPECT_FALSE(validator->ReadBlockAtOffset(
-      read_buffer.data(), validator->GetSize() - read_buffer.size(),
-      read_buffer.size()));
+      read_buffer, validator->GetSize() - read_buffer.size()));
   // Should not enlarge request at file end.
   EXPECT_EQ(validator->GetSize(), hints.GetLastRequstedRange().second);
   EXPECT_FALSE(validator->read_error());
@@ -145,7 +136,8 @@
   static const uint32_t kBufferSize = 3 * 1000;
   DataVector<uint8_t> buffer(kBufferSize);
 
-  EXPECT_FALSE(validator->ReadBlockAtOffset(buffer.data(), 5000, 100));
+  EXPECT_FALSE(
+      validator->ReadBlockAtOffset(pdfium::make_span(buffer).first(100), 5000));
   EXPECT_TRUE(validator->read_error());
   EXPECT_TRUE(validator->has_unavailable_data());
 }
@@ -164,8 +156,7 @@
   // read_error, and in this case we have not unavailable data. It is just error
   // of input params.
   EXPECT_FALSE(validator->ReadBlockAtOffset(
-      read_buffer.data(), std::numeric_limits<FX_FILESIZE>::max() - 1,
-      read_buffer.size()));
+      read_buffer, std::numeric_limits<FX_FILESIZE>::max() - 1));
   EXPECT_FALSE(validator->read_error());
   EXPECT_FALSE(validator->has_unavailable_data());
 }
@@ -184,8 +175,7 @@
   ASSERT_FALSE(validator->has_read_problems());
 
   // Data is unavailable
-  validator->ReadBlockAtOffset(test_data.data(), 0, 100);
-
+  validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0);
   EXPECT_TRUE(validator->has_read_problems());
   EXPECT_TRUE(validator->has_unavailable_data());
   EXPECT_FALSE(validator->read_error());
@@ -197,7 +187,7 @@
 
     file_avail.SetAvailableRange(0, 100);
     // Read fail.
-    validator->ReadBlockAtOffset(test_data.data(), 0, 100);
+    validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0);
     EXPECT_TRUE(validator->has_read_problems());
     EXPECT_TRUE(validator->has_unavailable_data());
     EXPECT_TRUE(validator->read_error());
@@ -223,8 +213,7 @@
   ASSERT_FALSE(validator->has_read_problems());
 
   // Data is unavailable
-  validator->ReadBlockAtOffset(test_data.data(), 0, 100);
-
+  validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0);
   EXPECT_TRUE(validator->has_read_problems());
   EXPECT_TRUE(validator->has_unavailable_data());
   EXPECT_FALSE(validator->read_error());
@@ -236,7 +225,7 @@
 
     file_avail.SetAvailableRange(0, 100);
     // Read fail.
-    validator->ReadBlockAtOffset(test_data.data(), 0, 100);
+    validator->ReadBlockAtOffset(pdfium::make_span(test_data).first(100), 0);
     EXPECT_TRUE(validator->has_read_problems());
     EXPECT_TRUE(validator->has_unavailable_data());
     EXPECT_TRUE(validator->read_error());
@@ -281,8 +270,7 @@
   EXPECT_FALSE(validator->has_unavailable_data());
 
   DataVector<uint8_t> read_buffer(100);
-  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer.data(), 5000,
-                                           read_buffer.size()));
+  EXPECT_TRUE(validator->ReadBlockAtOffset(read_buffer, 5000));
   // No new request on already available data.
   EXPECT_EQ(MakeRange(0, 0), hints.GetLastRequstedRange());
   EXPECT_FALSE(validator->read_error());
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream.cpp b/core/fpdfapi/parser/cpdf_seekablemultistream.cpp
index 1ec21b8..c99d079 100644
--- a/core/fpdfapi/parser/cpdf_seekablemultistream.cpp
+++ b/core/fpdfapi/parser/cpdf_seekablemultistream.cpp
@@ -33,9 +33,8 @@
   return dwSize.ValueOrDie();
 }
 
-bool CPDF_SeekableMultiStream::ReadBlockAtOffset(void* buffer,
-                                                 FX_FILESIZE offset,
-                                                 size_t size) {
+bool CPDF_SeekableMultiStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                                 FX_FILESIZE offset) {
   int32_t iCount = fxcrt::CollectionSize<int32_t>(m_Data);
   int32_t index = 0;
   while (index < iCount) {
@@ -47,14 +46,12 @@
     offset -= dwSize;
     index++;
   }
-  auto buffer_span = pdfium::make_span(static_cast<uint8_t*>(buffer), size);
   while (index < iCount) {
     auto acc_span = m_Data[index]->GetSpan();
-    size_t dwRead =
-        std::min<size_t>(buffer_span.size(), acc_span.size() - offset);
-    fxcrt::spancpy(buffer_span, acc_span.subspan(offset, dwRead));
-    buffer_span = buffer_span.subspan(dwRead);
-    if (buffer_span.empty())
+    size_t dwRead = std::min<size_t>(buffer.size(), acc_span.size() - offset);
+    fxcrt::spancpy(buffer, acc_span.subspan(offset, dwRead));
+    buffer = buffer.subspan(dwRead);
+    if (buffer.empty())
       return true;
 
     offset = 0;
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream.h b/core/fpdfapi/parser/cpdf_seekablemultistream.h
index 9c419ff..30d62d8 100644
--- a/core/fpdfapi/parser/cpdf_seekablemultistream.h
+++ b/core/fpdfapi/parser/cpdf_seekablemultistream.h
@@ -24,9 +24,8 @@
   // IFX_SeekableReadStream
   FX_FILESIZE GetPosition() override;
   FX_FILESIZE GetSize() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
   size_t ReadBlock(void* buffer, size_t size) override;
   bool IsEOF() override;
   bool Flush() override;
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
index a5819f7..5e63db0 100644
--- a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
@@ -19,7 +19,7 @@
 
   uint8_t output_buffer[16];
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 0, 0));
+  EXPECT_FALSE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0));
   EXPECT_EQ(0xbd, output_buffer[0]);
 }
 
@@ -31,7 +31,7 @@
 
   uint8_t output_buffer[16];
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 0, 0));
+  EXPECT_FALSE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0));
   EXPECT_EQ(0xbd, output_buffer[0]);
 }
 
@@ -63,31 +63,29 @@
 
   uint8_t output_buffer[16];
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0, 0));
+  EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 0}, 0));
   EXPECT_EQ(0xbd, output_buffer[0]);
 
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 1, 0));
+  EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 0}, 1));
   EXPECT_EQ(0xbd, output_buffer[0]);
 
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0, 1));
+  EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 1}, 0));
   EXPECT_EQ(0, memcmp(output_buffer, "o", 1));
   EXPECT_EQ(0xbd, output_buffer[1]);
 
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_TRUE(
-      fileread->ReadBlockAtOffset(output_buffer, 0, sizeof(output_buffer)));
+  EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 0));
   EXPECT_EQ(0, memcmp(output_buffer, "one two three!!!", 16));
 
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_TRUE(fileread->ReadBlockAtOffset(output_buffer, 2, 10));
+  EXPECT_TRUE(fileread->ReadBlockAtOffset({output_buffer, 10}, 2));
   EXPECT_EQ(0, memcmp(output_buffer, "e two thre", 10));
   EXPECT_EQ(0xbd, output_buffer[11]);
 
   memset(output_buffer, 0xbd, sizeof(output_buffer));
-  EXPECT_FALSE(
-      fileread->ReadBlockAtOffset(output_buffer, 1, sizeof(output_buffer)));
+  EXPECT_FALSE(fileread->ReadBlockAtOffset(output_buffer, 1));
   EXPECT_EQ(0, memcmp(output_buffer, "ne two three!!!", 15));
   EXPECT_EQ(0xbd, output_buffer[15]);
 }
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index 9ef997a..9d9c0e3 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -142,7 +142,7 @@
                               size_t size) const {
   CHECK(IsFileBased());
   return absl::get<RetainPtr<IFX_SeekableReadStream>>(data_)->ReadBlockAtOffset(
-      buf, offset, size);
+      {buf, size}, offset);
 }
 
 bool CPDF_Stream::HasFilter() const {
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
index 657bdee..ffbc42f 100644
--- a/core/fpdfapi/parser/cpdf_syntax_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
@@ -54,17 +54,16 @@
   ~ReadableSubStream() override = default;
 
   // IFX_SeekableReadStream overrides:
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override {
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override {
     FX_SAFE_FILESIZE safe_end = offset;
-    safe_end += size;
+    safe_end += buffer.size();
     // Check that requested range is valid, to prevent calling of ReadBlock
     // of original m_pFileRead with incorrect params.
     if (!safe_end.IsValid() || safe_end.ValueOrDie() > m_PartSize)
       return false;
 
-    return m_pFileRead->ReadBlockAtOffset(buffer, m_PartOffset + offset, size);
+    return m_pFileRead->ReadBlockAtOffset(buffer, m_PartOffset + offset);
   }
 
   FX_FILESIZE GetSize() override { return m_PartSize; }
@@ -122,8 +121,7 @@
     read_size = m_FileLen - read_pos;
 
   m_pFileBuf.resize(read_size);
-  if (!m_pFileAccess->ReadBlockAtOffset(m_pFileBuf.data(), read_pos,
-                                        read_size)) {
+  if (!m_pFileAccess->ReadBlockAtOffset(m_pFileBuf, read_pos)) {
     m_pFileBuf.clear();
     return false;
   }
@@ -166,7 +164,7 @@
 }
 
 bool CPDF_SyntaxParser::ReadBlock(uint8_t* pBuf, uint32_t size) {
-  if (!m_pFileAccess->ReadBlockAtOffset(pBuf, m_Pos + m_HeaderOffset, size))
+  if (!m_pFileAccess->ReadBlockAtOffset({pBuf, size}, m_Pos + m_HeaderOffset))
     return false;
   m_Pos += size;
   return true;
@@ -794,8 +792,7 @@
     // changing object lifetimes by handing `substream` to `pStream`, make a
     // copy of the data here.
     FixedUninitDataVector<uint8_t> data(substream->GetSize());
-    bool did_read = substream->ReadBlockAtOffset(data.writable_span().data(), 0,
-                                                 data.size());
+    bool did_read = substream->ReadBlockAtOffset(data.writable_span(), 0);
     CHECK(did_read);
     auto data_as_stream =
         pdfium::MakeRetain<CFX_ReadOnlyVectorStream>(std::move(data));
diff --git a/core/fpdfapi/parser/fpdf_parser_utility.cpp b/core/fpdfapi/parser/fpdf_parser_utility.cpp
index 99d2eab..d6110b8 100644
--- a/core/fpdfapi/parser/fpdf_parser_utility.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_utility.cpp
@@ -80,7 +80,7 @@
   static constexpr size_t kBufSize = 4;
   uint8_t buf[kBufSize];
   for (FX_FILESIZE offset = 0; offset <= 1024; ++offset) {
-    if (!pFile->ReadBlockAtOffset(buf, offset, kBufSize))
+    if (!pFile->ReadBlockAtOffset(buf, offset))
       return absl::nullopt;
 
     if (memcmp(buf, "%PDF", 4) == 0)
diff --git a/core/fxcodec/progressive_decoder.cpp b/core/fxcodec/progressive_decoder.cpp
index 2c4934f..c5f0109 100644
--- a/core/fxcodec/progressive_decoder.cpp
+++ b/core/fxcodec/progressive_decoder.cpp
@@ -1147,8 +1147,8 @@
     if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
       m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
 
-    if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBuffer(), m_offSet,
-                                    input_size)) {
+    if (!m_pFile->ReadBlockAtOffset({m_pCodecMemory->GetBuffer(), input_size},
+                                    m_offSet)) {
       m_status = FXCODEC_STATUS::kError;
       return false;
     }
@@ -1216,8 +1216,8 @@
     if (m_pCodecMemory && input_size > m_pCodecMemory->GetSize())
       m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(input_size);
 
-    bool bResult = m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBuffer(),
-                                              m_offSet, input_size);
+    bool bResult = m_pFile->ReadBlockAtOffset(
+        {m_pCodecMemory->GetBuffer(), input_size}, m_offSet);
     if (!bResult) {
       m_pDeviceBitmap = nullptr;
       m_pFile = nullptr;
@@ -1409,8 +1409,8 @@
       std::min<FX_FILESIZE>(m_pFile->GetSize(), kBlockSize));
   m_pCodecMemory = pdfium::MakeRetain<CFX_CodecMemory>(size);
   m_offSet = 0;
-  if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBuffer(), m_offSet,
-                                  size)) {
+  if (!m_pFile->ReadBlockAtOffset({m_pCodecMemory->GetBuffer(), size},
+                                  m_offSet)) {
     m_status = FXCODEC_STATUS::kError;
     return false;
   }
@@ -1480,8 +1480,9 @@
   }
 
   // Append new data past the bytes not yet processed by the codec.
-  if (!m_pFile->ReadBlockAtOffset(m_pCodecMemory->GetBuffer() + dwUnconsumed,
-                                  m_offSet, dwBytesToFetchFromFile)) {
+  if (!m_pFile->ReadBlockAtOffset(
+          {m_pCodecMemory->GetBuffer() + dwUnconsumed, dwBytesToFetchFromFile},
+          m_offSet)) {
     *err_status = FXCODEC_STATUS::kError;
     return false;
   }
diff --git a/core/fxcodec/tiff/tiff_decoder.cpp b/core/fxcodec/tiff/tiff_decoder.cpp
index d910cd3..7451fbe 100644
--- a/core/fxcodec/tiff/tiff_decoder.cpp
+++ b/core/fxcodec/tiff/tiff_decoder.cpp
@@ -119,9 +119,10 @@
     return 0;
 
   FX_FILESIZE offset = pTiffContext->offset();
-  if (!pTiffContext->io_in()->ReadBlockAtOffset(buf, offset, length))
+  if (!pTiffContext->io_in()->ReadBlockAtOffset(
+          {static_cast<uint8_t*>(buf), static_cast<size_t>(length)}, offset)) {
     return 0;
-
+  }
   pTiffContext->set_offset(increment.ValueOrDie());
   if (offset + length > pTiffContext->io_in()->GetSize()) {
     return pdfium::base::checked_cast<tsize_t>(
diff --git a/core/fxcrt/cfx_memorystream.cpp b/core/fxcrt/cfx_memorystream.cpp
index 5659644..b88c7bc 100644
--- a/core/fxcrt/cfx_memorystream.cpp
+++ b/core/fxcrt/cfx_memorystream.cpp
@@ -36,13 +36,12 @@
   return pdfium::make_span(m_data).first(m_nCurSize);
 }
 
-bool CFX_MemoryStream::ReadBlockAtOffset(void* buffer,
-                                         FX_FILESIZE offset,
-                                         size_t size) {
-  if (!buffer || offset < 0 || !size)
+bool CFX_MemoryStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                         FX_FILESIZE offset) {
+  if (buffer.empty() || offset < 0)
     return false;
 
-  FX_SAFE_SIZE_T new_pos = size;
+  FX_SAFE_SIZE_T new_pos = buffer.size();
   new_pos += offset;
   if (!new_pos.IsValid() || new_pos.ValueOrDefault(0) == 0 ||
       new_pos.ValueOrDie() > m_nCurSize) {
@@ -52,7 +51,8 @@
   m_nCurPos = new_pos.ValueOrDie();
   // Safe to cast `offset` because it was used to calculate `new_pos` above, and
   // `new_pos` is valid.
-  memcpy(buffer, &GetSpan()[static_cast<size_t>(offset)], size);
+  fxcrt::spancpy(buffer,
+                 GetSpan().subspan(static_cast<size_t>(offset), buffer.size()));
   return true;
 }
 
@@ -61,9 +61,10 @@
     return 0;
 
   size_t nRead = std::min(size, m_nCurSize - m_nCurPos);
-  if (!ReadBlockAtOffset(buffer, static_cast<int32_t>(m_nCurPos), nRead))
+  if (!ReadBlockAtOffset({static_cast<uint8_t*>(buffer), nRead},
+                         static_cast<int32_t>(m_nCurPos))) {
     return 0;
-
+  }
   return nRead;
 }
 
diff --git a/core/fxcrt/cfx_memorystream.h b/core/fxcrt/cfx_memorystream.h
index 2a46189..b1bbefa 100644
--- a/core/fxcrt/cfx_memorystream.h
+++ b/core/fxcrt/cfx_memorystream.h
@@ -20,9 +20,8 @@
   FX_FILESIZE GetSize() override;
   FX_FILESIZE GetPosition() override;
   bool IsEOF() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
   size_t ReadBlock(void* buffer, size_t size) override;
   bool WriteBlockAtOffset(const void* buffer,
                           FX_FILESIZE offset,
diff --git a/core/fxcrt/cfx_memorystream_unittest.cpp b/core/fxcrt/cfx_memorystream_unittest.cpp
index 520e89d..445e1c9 100644
--- a/core/fxcrt/cfx_memorystream_unittest.cpp
+++ b/core/fxcrt/cfx_memorystream_unittest.cpp
@@ -42,7 +42,7 @@
               testing::ElementsAre('a', 'b', 'c', '\0', '\0', 'a', 'b', 'c'));
 
   uint8_t buffer[4];
-  ASSERT_TRUE(stream->ReadBlockAtOffset(buffer, 2, sizeof(buffer)));
+  ASSERT_TRUE(stream->ReadBlockAtOffset(buffer, 2));
   ASSERT_THAT(buffer, testing::ElementsAre('c', '\0', '\0', 'a'));
 }
 
diff --git a/core/fxcrt/cfx_read_only_span_stream.cpp b/core/fxcrt/cfx_read_only_span_stream.cpp
index 5a8a066..ca78fa8 100644
--- a/core/fxcrt/cfx_read_only_span_stream.cpp
+++ b/core/fxcrt/cfx_read_only_span_stream.cpp
@@ -7,6 +7,7 @@
 #include "core/fxcrt/cfx_read_only_span_stream.h"
 
 #include "core/fxcrt/fx_safe_types.h"
+#include "core/fxcrt/span_util.h"
 #include "third_party/base/numerics/safe_conversions.h"
 
 CFX_ReadOnlySpanStream::CFX_ReadOnlySpanStream(pdfium::span<const uint8_t> span)
@@ -18,19 +19,18 @@
   return pdfium::base::checked_cast<FX_FILESIZE>(span_.size());
 }
 
-bool CFX_ReadOnlySpanStream::ReadBlockAtOffset(void* buffer,
-                                               FX_FILESIZE offset,
-                                               size_t size) {
-  if (!buffer || offset < 0 || size == 0)
+bool CFX_ReadOnlySpanStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                               FX_FILESIZE offset) {
+  if (buffer.empty() || offset < 0)
     return false;
 
-  FX_SAFE_SIZE_T pos = size;
+  FX_SAFE_SIZE_T pos = buffer.size();
   pos += offset;
   if (!pos.IsValid() || pos.ValueOrDie() > span_.size())
     return false;
 
-  auto copy_span =
-      span_.subspan(pdfium::base::checked_cast<size_t>(offset), size);
-  memcpy(buffer, copy_span.data(), copy_span.size());
+  fxcrt::spancpy(
+      buffer,
+      span_.subspan(pdfium::base::checked_cast<size_t>(offset), buffer.size()));
   return true;
 }
diff --git a/core/fxcrt/cfx_read_only_span_stream.h b/core/fxcrt/cfx_read_only_span_stream.h
index 9fb02bf..b1b30cd 100644
--- a/core/fxcrt/cfx_read_only_span_stream.h
+++ b/core/fxcrt/cfx_read_only_span_stream.h
@@ -17,9 +17,8 @@
 
   // IFX_SeekableReadStream:
   FX_FILESIZE GetSize() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
 
  private:
   explicit CFX_ReadOnlySpanStream(pdfium::span<const uint8_t> span);
diff --git a/core/fxcrt/cfx_read_only_string_stream.cpp b/core/fxcrt/cfx_read_only_string_stream.cpp
index beb32f5..62d5505 100644
--- a/core/fxcrt/cfx_read_only_string_stream.cpp
+++ b/core/fxcrt/cfx_read_only_string_stream.cpp
@@ -19,8 +19,7 @@
   return stream_->GetSize();
 }
 
-bool CFX_ReadOnlyStringStream::ReadBlockAtOffset(void* buffer,
-                                                 FX_FILESIZE offset,
-                                                 size_t size) {
-  return stream_->ReadBlockAtOffset(buffer, offset, size);
+bool CFX_ReadOnlyStringStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                                 FX_FILESIZE offset) {
+  return stream_->ReadBlockAtOffset(buffer, offset);
 }
diff --git a/core/fxcrt/cfx_read_only_string_stream.h b/core/fxcrt/cfx_read_only_string_stream.h
index d784228..fe4b26f 100644
--- a/core/fxcrt/cfx_read_only_string_stream.h
+++ b/core/fxcrt/cfx_read_only_string_stream.h
@@ -17,9 +17,8 @@
 
   // IFX_SeekableReadStream:
   FX_FILESIZE GetSize() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
 
  private:
   explicit CFX_ReadOnlyStringStream(ByteString data);
diff --git a/core/fxcrt/cfx_read_only_vector_stream.cpp b/core/fxcrt/cfx_read_only_vector_stream.cpp
index b64d3c5..d6a5bf0 100644
--- a/core/fxcrt/cfx_read_only_vector_stream.cpp
+++ b/core/fxcrt/cfx_read_only_vector_stream.cpp
@@ -24,8 +24,7 @@
   return stream_->GetSize();
 }
 
-bool CFX_ReadOnlyVectorStream::ReadBlockAtOffset(void* buffer,
-                                                 FX_FILESIZE offset,
-                                                 size_t size) {
-  return stream_->ReadBlockAtOffset(buffer, offset, size);
+bool CFX_ReadOnlyVectorStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                                 FX_FILESIZE offset) {
+  return stream_->ReadBlockAtOffset(buffer, offset);
 }
diff --git a/core/fxcrt/cfx_read_only_vector_stream.h b/core/fxcrt/cfx_read_only_vector_stream.h
index bc1816b..7e9e1e9 100644
--- a/core/fxcrt/cfx_read_only_vector_stream.h
+++ b/core/fxcrt/cfx_read_only_vector_stream.h
@@ -20,9 +20,8 @@
 
   // IFX_SeekableReadStream:
   FX_FILESIZE GetSize() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
 
  private:
   explicit CFX_ReadOnlyVectorStream(DataVector<uint8_t> data);
diff --git a/core/fxcrt/cfx_seekablestreamproxy.cpp b/core/fxcrt/cfx_seekablestreamproxy.cpp
index e096688..dc311ae 100644
--- a/core/fxcrt/cfx_seekablestreamproxy.cpp
+++ b/core/fxcrt/cfx_seekablestreamproxy.cpp
@@ -175,7 +175,7 @@
   if (iBufferSize <= 0)
     return 0;
 
-  if (!m_pStream->ReadBlockAtOffset(pBuffer, m_iPosition, iBufferSize))
+  if (!m_pStream->ReadBlockAtOffset({pBuffer, iBufferSize}, m_iPosition))
     return 0;
 
   FX_SAFE_FILESIZE new_pos = m_iPosition;
diff --git a/core/fxcrt/fx_stream.cpp b/core/fxcrt/fx_stream.cpp
index 01ea6d0..b593906 100644
--- a/core/fxcrt/fx_stream.cpp
+++ b/core/fxcrt/fx_stream.cpp
@@ -21,10 +21,9 @@
   FX_FILESIZE GetSize() override { return m_pFile->GetSize(); }
   bool IsEOF() override { return GetPosition() >= GetSize(); }
   FX_FILESIZE GetPosition() override { return m_pFile->GetPosition(); }
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override {
-    return m_pFile->ReadPos(buffer, size, offset) > 0;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override {
+    return m_pFile->ReadPos(buffer.data(), buffer.size(), offset) > 0;
   }
   size_t ReadBlock(void* buffer, size_t size) override {
     return m_pFile->Read(buffer, size);
diff --git a/core/fxcrt/fx_stream.h b/core/fxcrt/fx_stream.h
index e7cb020..290f06a 100644
--- a/core/fxcrt/fx_stream.h
+++ b/core/fxcrt/fx_stream.h
@@ -66,9 +66,8 @@
   virtual FX_FILESIZE GetPosition();
   virtual size_t ReadBlock(void* buffer, size_t size);
 
-  [[nodiscard]] virtual bool ReadBlockAtOffset(void* buffer,
-                                               FX_FILESIZE offset,
-                                               size_t size) = 0;
+  [[nodiscard]] virtual bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                               FX_FILESIZE offset) = 0;
 };
 
 class IFX_SeekableStream : public IFX_SeekableReadStream,
diff --git a/core/fxge/cfx_font.cpp b/core/fxge/cfx_font.cpp
index 31ba389..2224971 100644
--- a/core/fxge/cfx_font.cpp
+++ b/core/fxge/cfx_font.cpp
@@ -99,7 +99,7 @@
 
   IFX_SeekableReadStream* pFile =
       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
-  return pFile && pFile->ReadBlockAtOffset(buffer, offset, count) ? count : 0;
+  return pFile && pFile->ReadBlockAtOffset({buffer, count}, offset) ? count : 0;
 }
 
 void FTStreamClose(FXFT_StreamRec* stream) {}
diff --git a/fpdfsdk/cpdfsdk_customaccess.cpp b/fpdfsdk/cpdfsdk_customaccess.cpp
index f7f02e2..4f82823 100644
--- a/fpdfsdk/cpdfsdk_customaccess.cpp
+++ b/fpdfsdk/cpdfsdk_customaccess.cpp
@@ -18,21 +18,19 @@
   return m_FileAccess.m_FileLen;
 }
 
-bool CPDFSDK_CustomAccess::ReadBlockAtOffset(void* buffer,
-                                             FX_FILESIZE offset,
-                                             size_t size) {
-  if (!buffer || offset < 0 || !size)
+bool CPDFSDK_CustomAccess::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                             FX_FILESIZE offset) {
+  if (buffer.empty() || offset < 0)
     return false;
 
-  if (!pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(size))
+  if (!pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(buffer.size()))
     return false;
 
-  FX_SAFE_FILESIZE new_pos = size;
+  FX_SAFE_FILESIZE new_pos = buffer.size();
   new_pos += offset;
   return new_pos.IsValid() && new_pos.ValueOrDie() <= GetSize() &&
          m_FileAccess.m_GetBlock(
              m_FileAccess.m_Param,
-             pdfium::base::checked_cast<unsigned long>(offset),
-             static_cast<uint8_t*>(buffer),
-             pdfium::base::checked_cast<unsigned long>(size));
+             pdfium::base::checked_cast<unsigned long>(offset), buffer.data(),
+             pdfium::base::checked_cast<unsigned long>(buffer.size()));
 }
diff --git a/fpdfsdk/cpdfsdk_customaccess.h b/fpdfsdk/cpdfsdk_customaccess.h
index 6654343..734baeb 100644
--- a/fpdfsdk/cpdfsdk_customaccess.h
+++ b/fpdfsdk/cpdfsdk_customaccess.h
@@ -17,9 +17,8 @@
 
   // IFX_SeekableReadStream
   FX_FILESIZE GetSize() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
 
  private:
   explicit CPDFSDK_CustomAccess(FPDF_FILEACCESS* pFileAccess);
diff --git a/fpdfsdk/cpdfsdk_helpers.cpp b/fpdfsdk/cpdfsdk_helpers.cpp
index 852acd7..584a0b6 100644
--- a/fpdfsdk/cpdfsdk_helpers.cpp
+++ b/fpdfsdk/cpdfsdk_helpers.cpp
@@ -84,9 +84,8 @@
   FX_FILESIZE GetSize() override;
   bool IsEOF() override;
   FX_FILESIZE GetPosition() override;
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
   size_t ReadBlock(void* buffer, size_t size) override;
   bool WriteBlockAtOffset(const void* buffer,
                           FX_FILESIZE offset,
@@ -125,15 +124,15 @@
   return m_nCurPos;
 }
 
-bool FPDF_FileHandlerContext::ReadBlockAtOffset(void* buffer,
-                                                FX_FILESIZE offset,
-                                                size_t size) {
-  if (!buffer || !size || !m_pFS->ReadBlock)
+bool FPDF_FileHandlerContext::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                                FX_FILESIZE offset) {
+  if (buffer.empty() || !m_pFS->ReadBlock)
     return false;
 
-  if (m_pFS->ReadBlock(m_pFS->clientData, (FPDF_DWORD)offset, buffer,
-                       (FPDF_DWORD)size) == 0) {
-    m_nCurPos = offset + size;
+  if (m_pFS->ReadBlock(m_pFS->clientData, static_cast<FPDF_DWORD>(offset),
+                       buffer.data(),
+                       static_cast<FPDF_DWORD>(buffer.size())) == 0) {
+    m_nCurPos = offset + buffer.size();
     return true;
   }
   return false;
diff --git a/fpdfsdk/fpdf_dataavail.cpp b/fpdfsdk/fpdf_dataavail.cpp
index 5008a7b..e4f85eb 100644
--- a/fpdfsdk/fpdf_dataavail.cpp
+++ b/fpdfsdk/fpdf_dataavail.cpp
@@ -74,22 +74,21 @@
   // IFX_SeekableReadStream:
   FX_FILESIZE GetSize() override { return file_->m_FileLen; }
 
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override {
-    if (!buffer || offset < 0 || !size)
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override {
+    if (buffer.empty() || offset < 0)
       return false;
 
-    if (!pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(size))
+    if (!pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(buffer.size()))
       return false;
 
-    FX_SAFE_FILESIZE new_pos = size;
+    FX_SAFE_FILESIZE new_pos = buffer.size();
     new_pos += offset;
     return new_pos.IsValid() && new_pos.ValueOrDie() <= GetSize() &&
-           file_->m_GetBlock(file_->m_Param,
-                             pdfium::base::checked_cast<unsigned long>(offset),
-                             static_cast<uint8_t*>(buffer),
-                             pdfium::base::checked_cast<unsigned long>(size));
+           file_->m_GetBlock(
+               file_->m_Param,
+               pdfium::base::checked_cast<unsigned long>(offset), buffer.data(),
+               pdfium::base::checked_cast<unsigned long>(buffer.size()));
   }
 
  private:
diff --git a/testing/invalid_seekable_read_stream.cpp b/testing/invalid_seekable_read_stream.cpp
index 33f91a8..778783c 100644
--- a/testing/invalid_seekable_read_stream.cpp
+++ b/testing/invalid_seekable_read_stream.cpp
@@ -9,9 +9,8 @@
 
 InvalidSeekableReadStream::~InvalidSeekableReadStream() = default;
 
-bool InvalidSeekableReadStream::ReadBlockAtOffset(void* buffer,
-                                                  FX_FILESIZE offset,
-                                                  size_t size) {
+bool InvalidSeekableReadStream::ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                                                  FX_FILESIZE offset) {
   return false;
 }
 
diff --git a/testing/invalid_seekable_read_stream.h b/testing/invalid_seekable_read_stream.h
index 1b968a2..ae24b1a 100644
--- a/testing/invalid_seekable_read_stream.h
+++ b/testing/invalid_seekable_read_stream.h
@@ -14,9 +14,8 @@
   CONSTRUCT_VIA_MAKE_RETAIN;
 
   // IFX_SeekableReadStream overrides:
-  bool ReadBlockAtOffset(void* buffer,
-                         FX_FILESIZE offset,
-                         size_t size) override;
+  bool ReadBlockAtOffset(pdfium::span<uint8_t> buffer,
+                         FX_FILESIZE offset) override;
   FX_FILESIZE GetSize() override;
 
  private:
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index bbc4128..ff6e39e 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -383,7 +383,7 @@
 
   IFX_SeekableReadStream* pFile =
       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
-  if (!pFile->ReadBlockAtOffset(buffer, offset, count))
+  if (!pFile->ReadBlockAtOffset({buffer, count}, offset))
     return 0;
 
   return count;