Remove FXSYS_wcstof in favor of system wcstof().

Currently, this always copies, but we can avoid this in many (not all)
cases with a subsequent CL. There is a slight difference with large
numbers, so this is a check that thing still render properly.

Change-Id: Id4c9d061ed69ca59c5fed0e31cd5feb4574c5e6f
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/117331
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/fx_extension.cpp b/core/fxcrt/fx_extension.cpp
index e44879c..8a12e8f 100644
--- a/core/fxcrt/fx_extension.cpp
+++ b/core/fxcrt/fx_extension.cpp
@@ -6,12 +6,12 @@
 
 #include "core/fxcrt/fx_extension.h"
 
-#include <algorithm>
-#include <limits>
+#include <wchar.h>
 
 #include "core/fxcrt/check.h"
 #include "core/fxcrt/fx_system.h"
 #include "core/fxcrt/utf16.h"
+#include "core/fxcrt/widestring.h"
 
 namespace {
 
@@ -29,98 +29,16 @@
 }  // namespace
 
 float FXSYS_wcstof(const wchar_t* pwsStr, size_t nLength, size_t* pUsedLen) {
-  // SAFETY: TODO(tsepez): This is an enormous unsafe block, pretty hard to
-  // explain its soundness.
-  UNSAFE_BUFFERS({
-    DCHECK(pwsStr);
-    if (nLength == 0) {
-      return 0.0f;
-    }
-
-    size_t nUsedLen = 0;
-    bool bNegtive = false;
-    switch (pwsStr[nUsedLen]) {
-      case '-':
-        bNegtive = true;
-        [[fallthrough]];
-      case '+':
-        nUsedLen++;
-        break;
-    }
-
-    double dValue = 0.0f;
-    while (nUsedLen < nLength) {
-      wchar_t wch = pwsStr[nUsedLen];
-      if (!FXSYS_IsDecimalDigit(wch))
-        break;
-
-      dValue = dValue * 10.0f + (wch - L'0');
-      nUsedLen++;
-    }
-
-    if (nUsedLen < nLength && pwsStr[nUsedLen] == L'.') {
-      float fPrecise = 0.1f;
-      while (++nUsedLen < nLength) {
-        wchar_t wch = pwsStr[nUsedLen];
-        if (!FXSYS_IsDecimalDigit(wch)) {
-          break;
-        }
-
-        dValue += (wch - L'0') * fPrecise;
-        fPrecise *= 0.1f;
-      }
-    }
-
-    if (nUsedLen < nLength &&
-        (pwsStr[nUsedLen] == 'e' || pwsStr[nUsedLen] == 'E')) {
-      ++nUsedLen;
-
-      bool negative_exponent = false;
-      if (nUsedLen < nLength &&
-          (pwsStr[nUsedLen] == '-' || pwsStr[nUsedLen] == '+')) {
-        negative_exponent = pwsStr[nUsedLen] == '-';
-        ++nUsedLen;
-      }
-
-      int32_t exp_value = 0;
-      while (nUsedLen < nLength) {
-        wchar_t wch = pwsStr[nUsedLen];
-        if (!FXSYS_IsDecimalDigit(wch)) {
-          break;
-        }
-
-        exp_value = exp_value * 10.0f + (wch - L'0');
-        // Exponent is outside the valid range, fail.
-        if ((negative_exponent &&
-             -exp_value < std::numeric_limits<float>::min_exponent10) ||
-            (!negative_exponent &&
-             exp_value > std::numeric_limits<float>::max_exponent10)) {
-          if (pUsedLen) {
-            *pUsedLen = 0;
-          }
-          return 0.0f;
-        }
-
-        ++nUsedLen;
-      }
-
-      for (size_t i = exp_value; i > 0; --i) {
-        if (exp_value > 0) {
-          if (negative_exponent) {
-            dValue /= 10;
-          } else {
-            dValue *= 10;
-          }
-        }
-      }
-    }
-
-    if (pUsedLen) {
-      *pUsedLen = nUsedLen;
-    }
-
-    return static_cast<float>(bNegtive ? -dValue : dValue);
-  });
+  WideString copied(pwsStr, nLength);
+  wchar_t* endptr = nullptr;
+  float result = wcstof(copied.c_str(), &endptr);
+  if (result != result) {
+    result = 0.0f;  // Convert NAN to 0.0f;
+  }
+  if (pUsedLen) {
+    *pUsedLen = endptr - copied.c_str();
+  }
+  return result;
 }
 
 wchar_t* FXSYS_wcsncpy(wchar_t* dstStr, const wchar_t* srcStr, size_t count) {
diff --git a/core/fxcrt/fx_extension_unittest.cpp b/core/fxcrt/fx_extension_unittest.cpp
index 8f503c2..809c77e 100644
--- a/core/fxcrt/fx_extension_unittest.cpp
+++ b/core/fxcrt/fx_extension_unittest.cpp
@@ -136,10 +136,38 @@
   EXPECT_EQ(3u, used_len);
 
   used_len = 0;
+  EXPECT_FLOAT_EQ(12.0f, FXSYS_wcstof(L"+12", 3, &used_len));
+  EXPECT_EQ(3u, used_len);
+
+  used_len = 0;
+  EXPECT_FLOAT_EQ(123.0f, FXSYS_wcstof(L" 123", 4, &used_len));
+  EXPECT_EQ(4u, used_len);
+
+  used_len = 0;
+  EXPECT_FLOAT_EQ(123.0f, FXSYS_wcstof(L" 123 ", 5, &used_len));
+  EXPECT_EQ(4u, used_len);
+
+  used_len = 0;
+  EXPECT_FLOAT_EQ(1.0f, FXSYS_wcstof(L" 1 2 3 ", 7, &used_len));
+  EXPECT_EQ(2u, used_len);
+
+  used_len = 0;
   EXPECT_FLOAT_EQ(1.5362f, FXSYS_wcstof(L"1.5362", 6, &used_len));
   EXPECT_EQ(6u, used_len);
 
   used_len = 0;
+  EXPECT_FLOAT_EQ(1.0f, FXSYS_wcstof(L"1 .5362", 7, &used_len));
+  EXPECT_EQ(1u, used_len);
+
+  used_len = 0;
+  EXPECT_FLOAT_EQ(1.0f, FXSYS_wcstof(L"1. 5362", 7, &used_len));
+  EXPECT_EQ(2u, used_len);
+
+  used_len = 0;
+  EXPECT_FLOAT_EQ(1.5f, FXSYS_wcstof(L"1.5.3.6.2", 9, &used_len));
+  EXPECT_EQ(3u, used_len);
+
+  used_len = 0;
   EXPECT_FLOAT_EQ(0.875f, FXSYS_wcstof(L"0.875", 5, &used_len));
   EXPECT_EQ(5u, used_len);
 
@@ -152,12 +180,12 @@
   EXPECT_EQ(8u, used_len);
 
   used_len = 0;
-  EXPECT_FLOAT_EQ(0.0f, FXSYS_wcstof(L"1.234E100000000000000", 21, &used_len));
-  EXPECT_EQ(0u, used_len);
+  EXPECT_TRUE(isinf(FXSYS_wcstof(L"1.234E100000000000000", 21, &used_len)));
+  EXPECT_EQ(21u, used_len);
 
   used_len = 0;
   EXPECT_FLOAT_EQ(0.0f, FXSYS_wcstof(L"1.234E-128", 10, &used_len));
-  EXPECT_EQ(0u, used_len);
+  EXPECT_EQ(10u, used_len);
 
   // TODO(dsinclair): This should round as per IEEE 64-bit values.
   // EXPECT_EQ(L"123456789.01234567", FXSYS_wcstof(L"123456789.012345678"));