Convert BasicModule::A85Encode() to use DataVector.

Bug: pdfium:1872
Change-Id: I7b7e6265988947b072f5e04c2cce73fb3e3aedc2
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/97532
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcodec/basic/a85_unittest.cpp b/core/fxcodec/basic/a85_unittest.cpp
index 93b121e..e016a93 100644
--- a/core/fxcodec/basic/a85_unittest.cpp
+++ b/core/fxcodec/basic/a85_unittest.cpp
@@ -9,155 +9,122 @@
 #include <memory>
 
 #include "core/fxcodec/basic/basicmodule.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
+#include "core/fxcrt/data_vector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-TEST(fxcodec, A85TestBadInputs) {
-  const uint8_t src_buf[] = {1, 2, 3, 4};
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
-
-  // Error codes, not segvs, should callers pass us a nullptr pointer.
-  EXPECT_FALSE(BasicModule::A85Encode(src_buf, &dest_buf, nullptr));
-  EXPECT_FALSE(BasicModule::A85Encode(src_buf, nullptr, &dest_size));
-  EXPECT_FALSE(BasicModule::A85Encode({}, &dest_buf, &dest_size));
+TEST(fxcodec, A85EmptyInput) {
+  EXPECT_TRUE(BasicModule::A85Encode({}).empty());
 }
 
 // No leftover bytes, just translate 2 sets of symbols.
-TEST(fxcodec, A85TestBasic) {
+TEST(fxcodec, A85Basic) {
   // Make sure really big values don't break.
   const uint8_t src_buf[] = {1, 2, 3, 4, 255, 255, 255, 255};
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
-  EXPECT_TRUE(BasicModule::A85Encode(src_buf, &dest_buf, &dest_size));
+  DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf);
 
   // Should have 5 chars for each set of 4 and 2 terminators.
   const uint8_t expected_out[] = {33, 60, 78, 63, 43,  115,
                                   56, 87, 45, 33, 126, 62};
-  ASSERT_EQ(std::size(expected_out), dest_size);
+  ASSERT_EQ(std::size(expected_out), dest_buf.size());
 
   // Check the output
-  auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-  for (uint32_t i = 0; i < dest_size; i++)
-    EXPECT_EQ(expected_out[i], dest_buf_span[i]) << " at " << i;
+  for (uint32_t i = 0; i < dest_buf.size(); i++)
+    EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
 }
 
 // Leftover bytes.
-TEST(fxcodec, A85TestLeftoverBytes) {
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
-
+TEST(fxcodec, A85LeftoverBytes) {
   {
     // 1 Leftover Byte:
     const uint8_t src_buf_1leftover[] = {1, 2, 3, 4, 255};
-    EXPECT_TRUE(
-        BasicModule::A85Encode(src_buf_1leftover, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf_1leftover);
 
     // 5 chars for first symbol + 2 + 2 terminators.
     uint8_t expected_out_1leftover[] = {33, 60, 78, 63, 43, 114, 114, 126, 62};
-    ASSERT_EQ(std::size(expected_out_1leftover), dest_size);
+    ASSERT_EQ(std::size(expected_out_1leftover), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out_1leftover[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out_1leftover[i], dest_buf[i]) << " at " << i;
   }
 
   {
     // 2 Leftover bytes:
     const uint8_t src_buf_2leftover[] = {1, 2, 3, 4, 255, 254};
-    dest_buf.reset();
-    dest_size = 0;
-    EXPECT_TRUE(
-        BasicModule::A85Encode(src_buf_2leftover, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf_2leftover);
     // 5 chars for first symbol + 3 + 2 terminators.
     const uint8_t expected_out_2leftover[] = {33,  60, 78, 63,  43,
                                               115, 56, 68, 126, 62};
-    ASSERT_EQ(std::size(expected_out_2leftover), dest_size);
+    ASSERT_EQ(std::size(expected_out_2leftover), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out_2leftover[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out_2leftover[i], dest_buf[i]) << " at " << i;
   }
 
   {
     // 3 Leftover bytes:
     const uint8_t src_buf_3leftover[] = {1, 2, 3, 4, 255, 254, 253};
-    dest_buf.reset();
-    dest_size = 0;
-    EXPECT_TRUE(
-        BasicModule::A85Encode(src_buf_3leftover, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf_3leftover);
     // 5 chars for first symbol + 4 + 2 terminators.
     const uint8_t expected_out_3leftover[] = {33, 60, 78,  63,  43, 115,
                                               56, 77, 114, 126, 62};
-    ASSERT_EQ(std::size(expected_out_3leftover), dest_size);
+    ASSERT_EQ(std::size(expected_out_3leftover), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out_3leftover[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out_3leftover[i], dest_buf[i]) << " at " << i;
   }
 }
 
 // Test all zeros comes through as "z".
-TEST(fxcodec, A85TestZeros) {
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
-
+TEST(fxcodec, A85Zeros) {
   {
     // Make sure really big values don't break.
     const uint8_t src_buf[] = {1, 2, 3, 4, 0, 0, 0, 0};
-    EXPECT_TRUE(BasicModule::A85Encode(src_buf, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf);
 
     // Should have 5 chars for first set of 4 + 1 for z + 2 terminators.
     const uint8_t expected_out[] = {33, 60, 78, 63, 43, 122, 126, 62};
-    ASSERT_EQ(std::size(expected_out), dest_size);
+    ASSERT_EQ(std::size(expected_out), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out[i], dest_buf[i]) << " at " << i;
   }
 
   {
     // Should also work if it is at the start:
     const uint8_t src_buf_2[] = {0, 0, 0, 0, 1, 2, 3, 4};
-    dest_buf.reset();
-    dest_size = 0;
-    EXPECT_TRUE(BasicModule::A85Encode(src_buf_2, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf_2);
 
     // Should have 5 chars for set of 4 + 1 for z + 2 terminators.
     const uint8_t expected_out_2[] = {122, 33, 60, 78, 63, 43, 126, 62};
-    ASSERT_EQ(std::size(expected_out_2), dest_size);
+    ASSERT_EQ(std::size(expected_out_2), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out_2[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out_2[i], dest_buf[i]) << " at " << i;
   }
 
   {
     // Try with 2 leftover zero bytes. Make sure we don't get a "z".
     const uint8_t src_buf_3[] = {1, 2, 3, 4, 0, 0};
-    dest_buf.reset();
-    dest_size = 0;
-    EXPECT_TRUE(BasicModule::A85Encode(src_buf_3, &dest_buf, &dest_size));
+    DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf_3);
 
     // Should have 5 chars for set of 4 + 3 for last 2 + 2 terminators.
     const uint8_t expected_out_leftover[] = {33, 60, 78, 63,  43,
                                              33, 33, 33, 126, 62};
-    ASSERT_EQ(std::size(expected_out_leftover), dest_size);
+    ASSERT_EQ(std::size(expected_out_leftover), dest_buf.size());
 
     // Check the output
-    auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-    for (uint32_t i = 0; i < dest_size; i++)
-      EXPECT_EQ(expected_out_leftover[i], dest_buf_span[i]) << " at " << i;
+    for (uint32_t i = 0; i < dest_buf.size(); i++)
+      EXPECT_EQ(expected_out_leftover[i], dest_buf[i]) << " at " << i;
   }
 }
 
 // Make sure we get returns in the expected locations.
-TEST(fxcodec, A85TestLineBreaks) {
+TEST(fxcodec, A85LineBreaks) {
   // Make sure really big values don't break.
   uint8_t src_buf[131] = {0};
   // 1 full line + most of a line of normal symbols.
@@ -174,21 +141,18 @@
     src_buf[k + 2] = 3;
     src_buf[k + 3] = 4;
   }
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
 
   // Should succeed.
-  EXPECT_TRUE(BasicModule::A85Encode(src_buf, &dest_buf, &dest_size));
+  DataVector<uint8_t> dest_buf = BasicModule::A85Encode(src_buf);
 
   // Should have 75 chars in the first row plus 2 char return,
   // 76 chars in the second row plus 2 char return,
   // and 9 chars in the last row with 2 terminators.
-  ASSERT_EQ(166u, dest_size);
+  ASSERT_EQ(166u, dest_buf.size());
 
   // Check for the returns.
-  auto dest_buf_span = pdfium::make_span(dest_buf.get(), dest_size);
-  EXPECT_EQ(13, dest_buf_span[75]);
-  EXPECT_EQ(10, dest_buf_span[76]);
-  EXPECT_EQ(13, dest_buf_span[153]);
-  EXPECT_EQ(10, dest_buf_span[154]);
+  EXPECT_EQ(13, dest_buf[75]);
+  EXPECT_EQ(10, dest_buf[76]);
+  EXPECT_EQ(13, dest_buf[153]);
+  EXPECT_EQ(10, dest_buf[154]);
 }
diff --git a/core/fxcodec/basic/basicmodule.cpp b/core/fxcodec/basic/basicmodule.cpp
index d9285d0..ab2a003 100644
--- a/core/fxcodec/basic/basicmodule.cpp
+++ b/core/fxcodec/basic/basicmodule.cpp
@@ -308,17 +308,11 @@
 }
 
 // static
-bool BasicModule::A85Encode(pdfium::span<const uint8_t> src_span,
-                            std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
-                            uint32_t* dest_size) {
-  // Check inputs.
-  if (!dest_buf || !dest_size)
-    return false;
-
-  if (src_span.empty()) {
-    *dest_size = 0;
-    return false;
-  }
+DataVector<uint8_t> BasicModule::A85Encode(
+    pdfium::span<const uint8_t> src_span) {
+  DataVector<uint8_t> result;
+  if (src_span.empty())
+    return result;
 
   // Worst case: 5 output for each 4 input (plus up to 4 from leftover), plus
   // 2 character new lines each 75 output chars plus 2 termination chars. May
@@ -329,10 +323,10 @@
   estimated_size += 4;
   estimated_size += src_span.size() / 30;
   estimated_size += 2;
-  dest_buf->reset(FX_Alloc(uint8_t, estimated_size.ValueOrDie()));
+  result.resize(estimated_size.ValueOrDie());
 
   // Set up pointers.
-  uint8_t* out = dest_buf->get();
+  uint8_t* out = result.data();
   uint32_t pos = 0;
   uint32_t line_length = 0;
   while (src_span.size() >= 4 && pos < src_span.size() - 3) {
@@ -345,8 +339,8 @@
       line_length++;
     } else {  // Compute base 85 characters and add 33.
       for (int i = 4; i >= 0; i--) {
-        out[i] = (uint8_t)(val % 85) + 33;
-        val = val / 85;
+        out[i] = (val % 85) + 33;
+        val /= 85;
       }
       out += 5;
       line_length += 5;
@@ -367,8 +361,8 @@
     }
     for (int i = 4; i >= 0; i--) {
       if (i <= count)
-        out[i] = (uint8_t)(val % 85) + 33;
-      val = val / 85;
+        out[i] = (val % 85) + 33;
+      val /= 85;
     }
     out += count + 1;
   }
@@ -377,8 +371,10 @@
   out[0] = '~';
   out[1] = '>';
   out += 2;
-  *dest_size = pdfium::base::checked_cast<uint32_t>(out - dest_buf->get());
-  return true;
+  size_t new_size = out - result.data();
+  CHECK_LE(new_size, result.size());
+  result.resize(new_size);
+  return result;
 }
 
 }  // namespace fxcodec
diff --git a/core/fxcodec/basic/basicmodule.h b/core/fxcodec/basic/basicmodule.h
index a44621f..674c8ff 100644
--- a/core/fxcodec/basic/basicmodule.h
+++ b/core/fxcodec/basic/basicmodule.h
@@ -12,7 +12,6 @@
 #include <memory>
 
 #include "core/fxcrt/data_vector.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
 #include "third_party/base/span.h"
 
 namespace fxcodec {
@@ -31,9 +30,7 @@
   static DataVector<uint8_t> RunLengthEncode(
       pdfium::span<const uint8_t> src_span);
 
-  static bool A85Encode(pdfium::span<const uint8_t> src_span,
-                        std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
-                        uint32_t* dest_size);
+  static DataVector<uint8_t> A85Encode(pdfium::span<const uint8_t> src_span);
 
   BasicModule() = delete;
   BasicModule(const BasicModule&) = delete;
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index 0a6b9e8..8685915 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -879,13 +879,10 @@
 }
 
 void CFX_PSRenderer::WritePSBinary(pdfium::span<const uint8_t> data) {
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size;
-  if (m_pEncoderIface->pA85EncodeFunc(data, &dest_buf, &dest_size)) {
-    m_Output.write(reinterpret_cast<const char*>(dest_buf.get()), dest_size);
-  } else {
-    m_Output.write(reinterpret_cast<const char*>(data.data()), data.size());
-  }
+  DataVector<uint8_t> encoded_data = m_pEncoderIface->pA85EncodeFunc(data);
+  pdfium::span<const uint8_t> result =
+      encoded_data.empty() ? data : encoded_data;
+  m_Output.write(reinterpret_cast<const char*>(result.data()), result.size());
 }
 
 void CFX_PSRenderer::WriteStream(fxcrt::ostringstream& stream) {
diff --git a/core/fxge/win32/cfx_psrenderer.h b/core/fxge/win32/cfx_psrenderer.h
index 2031fd5..991716a 100644
--- a/core/fxge/win32/cfx_psrenderer.h
+++ b/core/fxge/win32/cfx_psrenderer.h
@@ -36,9 +36,7 @@
 struct FXDIB_ResampleOptions;
 
 struct EncoderIface {
-  bool (*pA85EncodeFunc)(pdfium::span<const uint8_t> src_buf,
-                         std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
-                         uint32_t* dest_size);
+  DataVector<uint8_t> (*pA85EncodeFunc)(pdfium::span<const uint8_t> src_buf);
   void (*pFaxEncodeFunc)(const uint8_t* src_buf,
                          int width,
                          int height,
diff --git a/testing/fuzzers/pdf_codec_a85_fuzzer.cc b/testing/fuzzers/pdf_codec_a85_fuzzer.cc
index f9ae1fe..3502955 100644
--- a/testing/fuzzers/pdf_codec_a85_fuzzer.cc
+++ b/testing/fuzzers/pdf_codec_a85_fuzzer.cc
@@ -3,14 +3,10 @@
 // found in the LICENSE file.
 
 #include <cstdint>
-#include <memory>
 
 #include "core/fxcodec/basic/basicmodule.h"
-#include "core/fxcrt/fx_memory_wrappers.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf;
-  uint32_t dest_size = 0;
-  BasicModule::A85Encode({data, size}, &dest_buf, &dest_size);
+  BasicModule::A85Encode({data, size});
   return 0;
 }