Added test for util.printx() and make it match spec.

R=dsinclair@chromium.org

Review URL: https://codereview.chromium.org/1837543002
diff --git a/fpdfsdk/javascript/PublicMethods.cpp b/fpdfsdk/javascript/PublicMethods.cpp
index b85111b..a4c1356 100644
--- a/fpdfsdk/javascript/PublicMethods.cpp
+++ b/fpdfsdk/javascript/PublicMethods.cpp
@@ -1424,39 +1424,31 @@
     return FALSE;
   }
 
-  std::string cFormat;
-  int iIndex = params[0].ToInt();
-
   CJS_EventHandler* pEvent = pContext->GetEventHandler();
   if (!pEvent->m_pValue)
     return FALSE;
-  CFX_WideString& Value = pEvent->Value();
-  std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str();
 
-  switch (iIndex) {
+  CFX_WideString wsSource = pEvent->Value();
+  CFX_WideString wsFormat;
+  switch (params[0].ToInt()) {
     case 0:
-      cFormat = "99999";
+      wsFormat = L"99999";
       break;
     case 1:
-      cFormat = "99999-9999";
+      wsFormat = L"99999-9999";
       break;
-    case 2: {
-      std::string NumberStr;
-      util::printx("9999999999", strSrc, NumberStr);
-      if (NumberStr.length() >= 10)
-        cFormat = "(999) 999-9999";
+    case 2:
+      if (util::printx(L"9999999999", wsSource).GetLength() >= 10)
+        wsFormat = L"(999) 999-9999";
       else
-        cFormat = "999-9999";
+        wsFormat = L"999-9999";
       break;
-    }
     case 3:
-      cFormat = "999-99-9999";
+      wsFormat = L"999-99-9999";
       break;
   }
 
-  std::string strDes;
-  util::printx(cFormat, strSrc, strDes);
-  Value = CFX_WideString::FromLocal(strDes.c_str());
+  pEvent->Value() = util::printx(wsFormat, wsSource);
   return TRUE;
 }
 
@@ -1578,22 +1570,15 @@
       cFormat = "99999";
       break;
     case 1:
-      // cFormat = "99999-9999";
       cFormat = "999999999";
       break;
-    case 2: {
-      std::string NumberStr;
-      util::printx("9999999999", strSrc, NumberStr);
+    case 2:
       if (strSrc.length() + wstrChange.length() > 7)
-        // cFormat = "(999) 999-9999";
         cFormat = "9999999999";
       else
-        // cFormat = "999-9999";
         cFormat = "9999999";
       break;
-    }
     case 3:
-      // cFormat = "999-99-9999";
       cFormat = "999999999";
       break;
   }
diff --git a/fpdfsdk/javascript/util.cpp b/fpdfsdk/javascript/util.cpp
index 30656cd..f7b2d7f 100644
--- a/fpdfsdk/javascript/util.cpp
+++ b/fpdfsdk/javascript/util.cpp
@@ -309,96 +309,113 @@
                      const std::vector<CJS_Value>& params,
                      CJS_Value& vRet,
                      CFX_WideString& sError) {
-  int iSize = params.size();
-  if (iSize < 2)
+  if (params.size() < 2) {
+    sError = JSGetStringFromID((CJS_Context*)cc, IDS_STRING_JSPARAMERROR);
     return FALSE;
-  CFX_WideString sFormat = params[0].ToCFXWideString();
-  CFX_WideString sSource = params[1].ToCFXWideString();
-  std::string cFormat = CFX_ByteString::FromUnicode(sFormat).c_str();
-  std::string cSource = CFX_ByteString::FromUnicode(sSource).c_str();
-  std::string cDest;
-  printx(cFormat, cSource, cDest);
-  vRet = cDest.c_str();
+  }
+  vRet = printx(params[0].ToCFXWideString(), params[1].ToCFXWideString());
   return TRUE;
 }
 
-void util::printx(const std::string& cFormat,
-                  const std::string& cSource2,
-                  std::string& cPurpose) {
-  std::string cSource(cSource2);
-  if (!cPurpose.empty())
-    // cPurpose.clear();
-    cPurpose.erase();
-  int itSource = 0;
-  int iSize = cSource.size();
-  for (int iIndex = 0; iIndex < (int)cFormat.size() && itSource < iSize;
-       iIndex++) {
-    char letter = cFormat[iIndex];
-    switch (letter) {
-      case '?':
-        cPurpose += cSource[itSource];
-        itSource++;
-        break;
-      case 'X': {
-        while (itSource < iSize) {
-          if (std::isdigit(cSource[itSource]) ||
-              (cSource[itSource] >= 'a' && cSource[itSource] <= 'z') ||
-              (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) {
-            cPurpose += cSource[itSource];
-            itSource++;
-            break;
-          }
-          itSource++;
+enum CaseMode { kPreserveCase, kUpperCase, kLowerCase };
+
+static FX_WCHAR TranslateCase(FX_WCHAR input, CaseMode eMode) {
+  if (eMode == kLowerCase && input >= 'A' && input <= 'Z')
+    return input | 0x20;
+  if (eMode == kUpperCase && input >= 'a' && input <= 'z')
+    return input & ~0x20;
+  return input;
+}
+
+CFX_WideString util::printx(const CFX_WideString& wsFormat,
+                            const CFX_WideString& wsSource) {
+  CFX_WideString wsResult;
+  FX_STRSIZE iSourceIdx = 0;
+  FX_STRSIZE iFormatIdx = 0;
+  CaseMode eCaseMode = kPreserveCase;
+  bool bEscaped = false;
+  while (iFormatIdx < wsFormat.GetLength()) {
+    if (bEscaped) {
+      bEscaped = false;
+      wsResult += wsFormat[iFormatIdx];
+      ++iFormatIdx;
+      continue;
+    }
+    switch (wsFormat[iFormatIdx]) {
+      case '\\': {
+        bEscaped = true;
+        ++iFormatIdx;
+      } break;
+      case '<': {
+        eCaseMode = kLowerCase;
+        ++iFormatIdx;
+      } break;
+      case '>': {
+        eCaseMode = kUpperCase;
+        ++iFormatIdx;
+      } break;
+      case '=': {
+        eCaseMode = kPreserveCase;
+        ++iFormatIdx;
+      } break;
+      case '?': {
+        if (iSourceIdx < wsSource.GetLength()) {
+          wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
+          ++iSourceIdx;
         }
-        break;
+        ++iFormatIdx;
+      } break;
+      case 'X': {
+        if (iSourceIdx < wsSource.GetLength()) {
+          if ((wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') ||
+              (wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') ||
+              (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) {
+            wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
+            ++iFormatIdx;
+          }
+          ++iSourceIdx;
+        } else {
+          ++iFormatIdx;
+        }
       } break;
       case 'A': {
-        while (itSource < iSize) {
-          if ((cSource[itSource] >= 'a' && cSource[itSource] <= 'z') ||
-              (cSource[itSource] >= 'A' && cSource[itSource] <= 'Z')) {
-            cPurpose += cSource[itSource];
-            itSource++;
-            break;
+        if (iSourceIdx < wsSource.GetLength()) {
+          if ((wsSource[iSourceIdx] >= 'a' && wsSource[iSourceIdx] <= 'z') ||
+              (wsSource[iSourceIdx] >= 'A' && wsSource[iSourceIdx] <= 'Z')) {
+            wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
+            ++iFormatIdx;
           }
-          itSource++;
+          ++iSourceIdx;
+        } else {
+          ++iFormatIdx;
         }
-        break;
       } break;
       case '9': {
-        while (itSource < iSize) {
-          if (std::isdigit(cSource[itSource])) {
-            cPurpose += cSource[itSource];
-            itSource++;
-            break;
+        if (iSourceIdx < wsSource.GetLength()) {
+          if (wsSource[iSourceIdx] >= '0' && wsSource[iSourceIdx] <= '9') {
+            wsResult += wsSource[iSourceIdx];
+            ++iFormatIdx;
           }
-          itSource++;
+          ++iSourceIdx;
+        } else {
+          ++iFormatIdx;
         }
-        break;
-      }
+      } break;
       case '*': {
-        cPurpose.append(cSource, itSource, iSize - itSource);
-        itSource = iSize - 1;
-        break;
-      }
-      case '\\':
-        break;
-      case '>': {
-        for (char& c : cSource)
-          c = toupper(c);
-        break;
-      }
-      case '<': {
-        for (char& c : cSource)
-          c = tolower(c);
-        break;
-      }
-      case '=':
-        break;
-      default:
-        cPurpose += letter;
-        break;
+        if (iSourceIdx < wsSource.GetLength()) {
+          wsResult += TranslateCase(wsSource[iSourceIdx], eCaseMode);
+          ++iSourceIdx;
+        } else {
+          ++iFormatIdx;
+        }
+      } break;
+      default: {
+        wsResult += wsFormat[iFormatIdx];
+        ++iFormatIdx;
+      } break;
     }
   }
+  return wsResult;
 }
 
 FX_BOOL util::scand(IJS_Context* cc,
diff --git a/fpdfsdk/javascript/util.h b/fpdfsdk/javascript/util.h
index 17f252d..3022efe 100644
--- a/fpdfsdk/javascript/util.h
+++ b/fpdfsdk/javascript/util.h
@@ -38,9 +38,8 @@
                      CJS_Value& vRet,
                      CFX_WideString& sError);
 
-  static void printx(const std::string& cFormat,
-                     const std::string& cSource,
-                     std::string& cPurpose);
+  static CFX_WideString printx(const CFX_WideString& cFormat,
+                               const CFX_WideString& cSource);
 };
 
 class CJS_Util : public CJS_Object {