Cleanup CJS_PublicMethods::ParseNumber

Original patch by tombergan.

The old version of this function was basically strtod with a few quirks:

1. It always interpreted ',' as '.' independent of locale. I kept this
   behavior, to be conservative.

2. It interpreted the first non-number character as a decimal point,
   unless there was a prior decimal point, in which case all characters
   up to that point are ignored. This would parse "123z4" as "123.4"
   and "123xy6" as "6". I did not keep this behavior -- in the new code,
   these examples all fail to parse.

The new ParseNumber was inlined into ConvertStringToNumber, which
returns true on success and (false, 0) on failure.

BUG=pdfium:361
R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/1582013002 .
diff --git a/fpdfsdk/src/javascript/Field.cpp b/fpdfsdk/src/javascript/Field.cpp
index 959e8dc..ebd3d33 100644
--- a/fpdfsdk/src/javascript/Field.cpp
+++ b/fpdfsdk/src/javascript/Field.cpp
@@ -2741,13 +2741,8 @@
         CFX_WideString swValue = pFormField->GetValue();
 
         double dRet;
-        FX_BOOL bDot;
-        if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet,
-                                                     bDot)) {
-          if (bDot)
-            vp << dRet;
-          else
-            vp << dRet;
+        if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet)) {
+          vp << dRet;
         } else {
           vp << swValue;
         }
@@ -2769,13 +2764,8 @@
           CFX_WideString swValue = pFormField->GetValue();
 
           double dRet;
-          FX_BOOL bDot;
-          if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet,
-                                                       bDot)) {
-            if (bDot)
-              vp << dRet;
-            else
-              vp << dRet;
+          if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet)) {
+            vp << dRet;
           } else {
             vp << swValue;
           }
@@ -2790,9 +2780,7 @@
 
           CFX_WideString swValue = pFormField->GetControl(i)->GetExportValue();
           double dRet;
-          FX_BOOL bDotDummy;
-          if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet,
-                                                       bDotDummy)) {
+          if (CJS_PublicMethods::ConvertStringToNumber(swValue.c_str(), dRet)) {
             vp << dRet;
           } else {
             vp << swValue;
diff --git a/fpdfsdk/src/javascript/PublicMethods.cpp b/fpdfsdk/src/javascript/PublicMethods.cpp
index d2f7fb0..9e5ad5d 100644
--- a/fpdfsdk/src/javascript/PublicMethods.cpp
+++ b/fpdfsdk/src/javascript/PublicMethods.cpp
@@ -194,147 +194,38 @@
   return StrRTrim(StrLTrim(pStr));
 }
 
-double CJS_PublicMethods::ParseNumber(const FX_WCHAR* swSource,
-                                      FX_BOOL& bAllDigits,
-                                      FX_BOOL& bDot,
-                                      FX_BOOL& bSign,
-                                      FX_BOOL& bKXJS) {
-  bDot = FALSE;
-  bSign = FALSE;
-  bKXJS = FALSE;
+FX_BOOL CJS_PublicMethods::ConvertStringToNumber(const FX_WCHAR* swSource,
+                                                 double& dRet) {
+  CFX_ByteString sDigits = CFX_WideString(swSource).UTF8Encode();
 
-  FX_BOOL bDigitExist = FALSE;
-
-  const FX_WCHAR* p = swSource;
-  wchar_t c;
-
-  const FX_WCHAR* pStart = NULL;
-  const FX_WCHAR* pEnd = NULL;
-
-  while ((c = *p)) {
-    if (!pStart && c != L' ') {
-      pStart = p;
-    }
-
-    pEnd = p;
-    p++;
+  // Always interpret "," as "." independent of the locale.
+  for (FX_STRSIZE k = 0; k < sDigits.GetLength(); k++) {
+    if (sDigits[k] == ',')
+      sDigits.SetAt(k, '.');
   }
 
-  if (!pStart) {
-    bAllDigits = FALSE;
-    return 0;
+  // Parse a number, ignoring leading and trailing whitespace.
+  // Fail if there is trailing garbage.
+  const char* pStart = sDigits.c_str();
+  const char* pEnd = NULL;
+  dRet = strtod(pStart, const_cast<char**>(&pEnd));
+  if (pEnd == pStart) {
+    return FALSE;
   }
-
-  while (pEnd != pStart) {
-    if (*pEnd == L' ')
-      pEnd--;
-    else
-      break;
-  }
-
-  double dRet = 0;
-  p = pStart;
-  bAllDigits = TRUE;
-  CFX_WideString swDigits;
-
-  while (p <= pEnd) {
-    c = *p;
-
-    if (FXSYS_iswdigit(c)) {
-      swDigits += c;
-      bDigitExist = TRUE;
-    } else {
-      switch (c) {
-        case L' ':
-          bAllDigits = FALSE;
-          break;
-        case L'.':
-        case L',':
-          if (!bDot) {
-            if (bDigitExist) {
-              swDigits += L'.';
-            } else {
-              swDigits += L'0';
-              swDigits += L'.';
-              bDigitExist = TRUE;
-            }
-
-            bDot = TRUE;
-            break;
-          }
-        case 'e':
-        case 'E':
-          if (!bKXJS) {
-            p++;
-            c = *p;
-            if (c == '+' || c == '-') {
-              bKXJS = TRUE;
-              swDigits += 'e';
-              swDigits += c;
-            }
-            break;
-          }
-        case L'-':
-          if (!bDigitExist && !bSign) {
-            swDigits += c;
-            bSign = TRUE;
-            break;
-          }
-        default:
-          bAllDigits = FALSE;
-
-          if (p != pStart && !bDot && bDigitExist) {
-            swDigits += L'.';
-            bDot = TRUE;
-          } else {
-            bDot = FALSE;
-            bDigitExist = FALSE;
-            swDigits = L"";
-          }
-          break;
-      }
-    }
-
-    p++;
-  }
-
-  if (swDigits.GetLength() > 0 && swDigits.GetLength() < 17) {
-    CFX_ByteString sDigits = swDigits.UTF8Encode();
-
-    if (bKXJS) {
-      dRet = atof(sDigits);
-    } else {
-      if (bDot) {
-        char* pStopString;
-        dRet = ::strtod(sDigits, &pStopString);
-      } else {
-        dRet = atol(sDigits);
-      }
+  for (; *pEnd; pEnd++) {
+    if (!isspace(*pEnd)) {
+      dRet = 0;
+      return FALSE;
     }
   }
 
-  return dRet;
+  return TRUE;
 }
 
 double CJS_PublicMethods::ParseStringToNumber(const FX_WCHAR* swSource) {
-  FX_BOOL bAllDigits = FALSE;
-  FX_BOOL bDot = FALSE;
-  FX_BOOL bSign = FALSE;
-  FX_BOOL bKXJS = FALSE;
-
-  return ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS);
-}
-
-FX_BOOL CJS_PublicMethods::ConvertStringToNumber(const FX_WCHAR* swSource,
-                                                 double& dRet,
-                                                 FX_BOOL& bDot) {
-  FX_BOOL bAllDigits = FALSE;
-  FX_BOOL bSign = FALSE;
-  FX_BOOL bKXJS = FALSE;
-
-  dRet = ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS);
-
-  return bAllDigits;
+  double dRet;
+  ConvertStringToNumber(swSource, dRet);
+  return dRet;
 }
 
 CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(CJS_Runtime* pRuntime,
diff --git a/fpdfsdk/src/javascript/PublicMethods.h b/fpdfsdk/src/javascript/PublicMethods.h
index 013c4ce..0172cba 100644
--- a/fpdfsdk/src/javascript/PublicMethods.h
+++ b/fpdfsdk/src/javascript/PublicMethods.h
@@ -144,18 +144,11 @@
                                 bool* bWrongFormat);
   static CFX_WideString MakeFormatDate(double dDate,
                                        const CFX_WideString& format);
-  static FX_BOOL ConvertStringToNumber(const FX_WCHAR* swSource,
-                                       double& dRet,
-                                       FX_BOOL& bDot);
+  static FX_BOOL ConvertStringToNumber(const FX_WCHAR* swSource, double& dRet);
   static double ParseStringToNumber(const FX_WCHAR* swSource);
   static double ParseNormalDate(const CFX_WideString& value,
                                 bool* bWrongFormat);
   static double MakeInterDate(CFX_WideString strValue);
-  static double ParseNumber(const FX_WCHAR* swSource,
-                            FX_BOOL& bAllDigits,
-                            FX_BOOL& bDot,
-                            FX_BOOL& bSign,
-                            FX_BOOL& bKXJS);
 
  public:
   static CFX_WideString StrLTrim(const FX_WCHAR* pStr);
diff --git a/testing/resources/javascript/bug_361_expected.txt b/testing/resources/javascript/bug_361_expected.txt
index f7f7a56..da92562 100644
--- a/testing/resources/javascript/bug_361_expected.txt
+++ b/testing/resources/javascript/bug_361_expected.txt
@@ -12,31 +12,31 @@
 Alert: Answer for "4 3 2 1" is: string 4 3 2 1
 Alert: Answer for "-4" is: number -4
 Alert: Answer for "23.00000001" is: number 23.00000001
-Alert: Answer for "23.00000000000000001" is: number 0
+Alert: Answer for "23.00000000000000001" is: number 23
 Alert: Answer for "4e+25" is: number 4e+25
-Alert: Answer for "40000000000000000000000000" is: number 0
+Alert: Answer for "40000000000000000000000000" is: number 4e+25
 Alert: Answer for "25,5" is: number 25.5
 Alert: Answer for "1e+5" is: number 100000
-Alert: Answer for "1e5" is: number 1
+Alert: Answer for "1e5" is: number 100000
 Alert: Answer for "1e-5" is: number 0.00001
 Alert: Answer for "-1e-5" is: number -0.00001
-Alert: Answer for "1.2e5" is: number 1.2
-Alert: Answer for "Infinity" is: string Infinity
-Alert: Answer for "Infinity" is: string Infinity
-Alert: Answer for "INFINITY" is: string INFINITY
-Alert: Answer for "INF" is: string INF
-Alert: Answer for "NaN" is: string NaN
-Alert: Answer for "NaN" is: string NaN
-Alert: Answer for "NAN" is: string NAN
-Alert: Answer for "0x100" is: string 0x100
-Alert: Answer for "0x100.1" is: string 0x100.1
-Alert: Answer for "0x100,1" is: string 0x100,1
+Alert: Answer for "1.2e5" is: number 120000
+Alert: Answer for "Infinity" is: number Infinity
+Alert: Answer for "Infinity" is: number Infinity
+Alert: Answer for "INFINITY" is: number Infinity
+Alert: Answer for "INF" is: number Infinity
+Alert: Answer for "NaN" is: number NaN
+Alert: Answer for "NaN" is: number NaN
+Alert: Answer for "NAN" is: number NaN
+Alert: Answer for "0x100" is: number 256
+Alert: Answer for "0x100.1" is: number 256.0625
+Alert: Answer for "0x100,1" is: number 256.0625
 Alert: Answer for "0x100x1" is: string 0x100x1
 Alert: Answer for "123x6" is: string 123x6
 Alert: Answer for "123xy6" is: string 123xy6
 Alert: Answer for "123.y6" is: string 123.y6
-Alert: Answer for "1,000,000" is: number 1
-Alert: Answer for "1.2.3" is: number 1.2
+Alert: Answer for "1,000,000" is: string 1,000,000
+Alert: Answer for "1.2.3" is: string 1.2.3
 Alert: Answer for "1-3" is: string 1-3
 Alert: Answer for "1+3" is: string 1+3
 Alert: Answer for "1.-3" is: string 1.-3