Remove hand-written bsearch from cfx_xmlsyntaxparser.cpp

Convert IsXMLNameChar() to static method for easier testing
without namespace pollution.

Change-Id: I004557e74fde94d3582b0a2326e5e68b907b9690
Reviewed-on: https://pdfium-review.googlesource.com/4397
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/xml/cfx_xmlsyntaxparser.cpp b/core/fxcrt/xml/cfx_xmlsyntaxparser.cpp
index aa455d5..ac3f1b5 100644
--- a/core/fxcrt/xml/cfx_xmlsyntaxparser.cpp
+++ b/core/fxcrt/xml/cfx_xmlsyntaxparser.cpp
@@ -7,6 +7,7 @@
 #include "core/fxcrt/xml/cfx_xmlsyntaxparser.h"
 
 #include <algorithm>
+#include <iterator>
 
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_safe_types.h"
@@ -35,21 +36,6 @@
     {0xF900, 0xFDCF, true}, {0xFDF0, 0xFFFD, true},
 };
 
-bool IsXMLNameChar(wchar_t ch, bool bFirstChar) {
-  int32_t iStart = 0;
-  int32_t iEnd = FX_ArraySize(g_XMLNameChars) - 1;
-  while (iStart <= iEnd) {
-    int32_t iMid = (iStart + iEnd) / 2;
-    if (ch < g_XMLNameChars[iMid].wStart) {
-      iEnd = iMid - 1;
-    } else if (ch > g_XMLNameChars[iMid].wEnd) {
-      iStart = iMid + 1;
-    } else {
-      return bFirstChar ? g_XMLNameChars[iMid].bStartChar : true;
-    }
-  }
-  return false;
-}
 
 int32_t GetUTF8EncodeLength(const std::vector<wchar_t>& src,
                             FX_FILESIZE iSrcLen) {
@@ -79,6 +65,15 @@
 
 }  // namespace
 
+// static
+bool CFX_XMLSyntaxParser::IsXMLNameChar(wchar_t ch, bool bFirstChar) {
+  auto* it = std::lower_bound(
+      std::begin(g_XMLNameChars), std::end(g_XMLNameChars), ch,
+      [](const FX_XMLNAMECHAR& arg, wchar_t ch) { return arg.wEnd < ch; });
+  return it != std::end(g_XMLNameChars) && ch >= it->wStart &&
+         (!bFirstChar || it->bStartChar);
+}
+
 CFX_XMLSyntaxParser::CFX_XMLSyntaxParser(
     const CFX_RetainPtr<CFX_SeekableStreamProxy>& pStream)
     : m_pStream(pStream),
diff --git a/core/fxcrt/xml/cfx_xmlsyntaxparser.h b/core/fxcrt/xml/cfx_xmlsyntaxparser.h
index 519f283..32e55f1 100644
--- a/core/fxcrt/xml/cfx_xmlsyntaxparser.h
+++ b/core/fxcrt/xml/cfx_xmlsyntaxparser.h
@@ -36,6 +36,8 @@
 
 class CFX_XMLSyntaxParser {
  public:
+  static bool IsXMLNameChar(wchar_t ch, bool bFirstChar);
+
   explicit CFX_XMLSyntaxParser(
       const CFX_RetainPtr<CFX_SeekableStreamProxy>& pStream);
   ~CFX_XMLSyntaxParser();
diff --git a/core/fxcrt/xml/cfx_xmlsyntaxparser_unittest.cpp b/core/fxcrt/xml/cfx_xmlsyntaxparser_unittest.cpp
index 60c0d34..09d4fea 100644
--- a/core/fxcrt/xml/cfx_xmlsyntaxparser_unittest.cpp
+++ b/core/fxcrt/xml/cfx_xmlsyntaxparser_unittest.cpp
@@ -525,3 +525,20 @@
 
   ASSERT_EQ(FX_XmlSyntaxResult::EndOfString, parser.DoSyntaxParse());
 }
+
+TEST_F(CFX_XMLSyntaxParserTest, IsXMLNameChar) {
+  EXPECT_FALSE(CFX_XMLSyntaxParser::IsXMLNameChar(L'-', true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(L'-', false));
+
+  EXPECT_FALSE(CFX_XMLSyntaxParser::IsXMLNameChar(0x2069, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0x2070, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0x2073, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0x218F, true));
+  EXPECT_FALSE(CFX_XMLSyntaxParser::IsXMLNameChar(0x2190, true));
+
+  EXPECT_FALSE(CFX_XMLSyntaxParser::IsXMLNameChar(0xFDEF, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0xFDF0, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0xFDF1, true));
+  EXPECT_TRUE(CFX_XMLSyntaxParser::IsXMLNameChar(0xFFFD, true));
+  EXPECT_FALSE(CFX_XMLSyntaxParser::IsXMLNameChar(0xFFFE, true));
+}