Add tests for CMap_GetCode and CMap_GetCodeRange.

This CL adds tests for the CMap_GetCode and CMap_GetCodeRange methods. To do
so, it moves the methods to be static private members of CPDF_CMapParser and
makes the test class a friend.

R=tsepez@chromium.org

Review URL: https://codereview.chromium.org/1414013005 .
diff --git a/BUILD.gn b/BUILD.gn
index 0dc9148..cdf6d6d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -714,6 +714,7 @@
 
 test("pdfium_unittests") {
   sources = [
+    "core/src/fpdfapi/fpdf_font/fpdf_font_cid_unittest.cpp",
     "core/src/fpdfapi/fpdf_font/fpdf_font_unittest.cpp",
     "core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp",
     "core/src/fxcodec/codec/fx_codec_jpx_unittest.cpp",
diff --git a/core/src/fpdfapi/fpdf_font/font_int.h b/core/src/fpdfapi/fpdf_font/font_int.h
index 559027b..c7a00dc 100644
--- a/core/src/fpdfapi/fpdf_font/font_int.h
+++ b/core/src/fpdfapi/fpdf_font/font_int.h
@@ -77,6 +77,14 @@
   CFX_BinaryBuf m_AddMaps;
 
  private:
+  friend class fpdf_font_cid_CMap_GetCode_Test;
+  friend class fpdf_font_cid_CMap_GetCodeRange_Test;
+
+  static FX_DWORD CMap_GetCode(const CFX_ByteStringC& word);
+  static bool CMap_GetCodeRange(CMap_CodeRange& range,
+                                const CFX_ByteStringC& first,
+                                const CFX_ByteStringC& second);
+
   CPDF_CMap* m_pCMap;
   int m_Status;
   int m_CodeSeq;
diff --git a/core/src/fpdfapi/fpdf_font/fpdf_font_cid.cpp b/core/src/fpdfapi/fpdf_font/fpdf_font_cid.cpp
index 02f0933..43125d7 100644
--- a/core/src/fpdfapi/fpdf_font/fpdf_font_cid.cpp
+++ b/core/src/fpdfapi/fpdf_font/fpdf_font_cid.cpp
@@ -185,78 +185,6 @@
   return CIDSET_UNKNOWN;
 }
 
-FX_DWORD CMap_GetCode(const CFX_ByteStringC& word) {
-  int num = 0;
-  if (word.GetAt(0) == '<') {
-    for (int i = 1; i < word.GetLength(); i++) {
-      uint8_t digit = word.GetAt(i);
-      if (digit >= '0' && digit <= '9') {
-        digit = digit - '0';
-      } else if (digit >= 'a' && digit <= 'f') {
-        digit = digit - 'a' + 10;
-      } else if (digit >= 'A' && digit <= 'F') {
-        digit = digit - 'A' + 10;
-      } else {
-        return num;
-      }
-      num = num * 16 + digit;
-    }
-  } else {
-    for (int i = 0; i < word.GetLength(); i++) {
-      if (word.GetAt(i) < '0' || word.GetAt(i) > '9') {
-        return num;
-      }
-      num = num * 10 + word.GetAt(i) - '0';
-    }
-  }
-  return num;
-}
-
-bool CMap_GetCodeRange(CMap_CodeRange& range,
-                       const CFX_ByteStringC& first,
-                       const CFX_ByteStringC& second) {
-  if (first.GetLength() == 0 || first.GetAt(0) != '<')
-    return false;
-
-  int i;
-  for (i = 1; i < first.GetLength(); ++i) {
-    if (first.GetAt(i) == '>') {
-      break;
-    }
-  }
-  range.m_CharSize = (i - 1) / 2;
-  if (range.m_CharSize > 4)
-    return false;
-
-  for (i = 0; i < range.m_CharSize; ++i) {
-    uint8_t digit1 = first.GetAt(i * 2 + 1);
-    uint8_t digit2 = first.GetAt(i * 2 + 2);
-    uint8_t byte = (digit1 >= '0' && digit1 <= '9')
-                       ? (digit1 - '0')
-                       : ((digit1 & 0xdf) - 'A' + 10);
-    byte = byte * 16 + ((digit2 >= '0' && digit2 <= '9')
-                            ? (digit2 - '0')
-                            : ((digit2 & 0xdf) - 'A' + 10));
-    range.m_Lower[i] = byte;
-  }
-
-  FX_DWORD size = second.GetLength();
-  for (i = 0; i < range.m_CharSize; ++i) {
-    uint8_t digit1 =
-        ((FX_DWORD)i * 2 + 1 < size) ? second.GetAt((FX_STRSIZE)i * 2 + 1) : 0;
-    uint8_t digit2 =
-        ((FX_DWORD)i * 2 + 2 < size) ? second.GetAt((FX_STRSIZE)i * 2 + 2) : 0;
-    uint8_t byte = (digit1 >= '0' && digit1 <= '9')
-                       ? (digit1 - '0')
-                       : ((digit1 & 0xdf) - 'A' + 10);
-    byte = byte * 16 + ((digit2 >= '0' && digit2 <= '9')
-                            ? (digit2 - '0')
-                            : ((digit2 & 0xdf) - 'A' + 10));
-    range.m_Upper[i] = byte;
-  }
-  return true;
-}
-
 CFX_ByteString CMap_GetString(const CFX_ByteStringC& word) {
   return word.Mid(1, word.GetLength() - 2);
 }
@@ -769,6 +697,82 @@
   }
   m_LastWord = word;
 }
+
+FX_DWORD CPDF_CMapParser::CMap_GetCode(const CFX_ByteStringC& word) {
+  int num = 0;
+  if (word.GetAt(0) == '<') {
+    for (int i = 1; i < word.GetLength(); i++) {
+      uint8_t digit = word.GetAt(i);
+      if (digit >= '0' && digit <= '9') {
+        digit = digit - '0';
+      } else if (digit >= 'a' && digit <= 'f') {
+        digit = digit - 'a' + 10;
+      } else if (digit >= 'A' && digit <= 'F') {
+        digit = digit - 'A' + 10;
+      } else {
+        return num;
+      }
+      num = num * 16 + digit;
+    }
+  } else {
+    for (int i = 0; i < word.GetLength(); i++) {
+      if (word.GetAt(i) < '0' || word.GetAt(i) > '9') {
+        return num;
+      }
+      num = num * 10 + word.GetAt(i) - '0';
+    }
+  }
+  return num;
+}
+
+// Static.
+bool CPDF_CMapParser::CMap_GetCodeRange(CMap_CodeRange& range,
+                                        const CFX_ByteStringC& first,
+                                        const CFX_ByteStringC& second) {
+  if (first.GetLength() == 0 || first.GetAt(0) != '<')
+    return false;
+
+  int i;
+  for (i = 1; i < first.GetLength(); ++i) {
+    if (first.GetAt(i) == '>') {
+      break;
+    }
+  }
+  range.m_CharSize = (i - 1) / 2;
+  if (range.m_CharSize > 4)
+    return false;
+
+  for (i = 0; i < range.m_CharSize; ++i) {
+    uint8_t digit1 = first.GetAt(i * 2 + 1);
+    uint8_t digit2 = first.GetAt(i * 2 + 2);
+    uint8_t byte = (digit1 >= '0' && digit1 <= '9')
+                       ? (digit1 - '0')
+                       : ((digit1 & 0xdf) - 'A' + 10);
+    byte = byte * 16 + ((digit2 >= '0' && digit2 <= '9')
+                            ? (digit2 - '0')
+                            : ((digit2 & 0xdf) - 'A' + 10));
+    range.m_Lower[i] = byte;
+  }
+
+  FX_DWORD size = second.GetLength();
+  for (i = 0; i < range.m_CharSize; ++i) {
+    uint8_t digit1 = ((FX_DWORD)i * 2 + 1 < size)
+                         ? second.GetAt((FX_STRSIZE)i * 2 + 1)
+                         : '0';
+    uint8_t digit2 = ((FX_DWORD)i * 2 + 2 < size)
+                         ? second.GetAt((FX_STRSIZE)i * 2 + 2)
+                         : '0';
+    uint8_t byte = (digit1 >= '0' && digit1 <= '9')
+                       ? (digit1 - '0')
+                       : ((digit1 & 0xdf) - 'A' + 10);
+    byte = byte * 16 + ((digit2 >= '0' && digit2 <= '9')
+                            ? (digit2 - '0')
+                            : ((digit2 & 0xdf) - 'A' + 10));
+    range.m_Upper[i] = byte;
+  }
+  return true;
+}
+
 CPDF_CMap::CPDF_CMap() {
   m_Charset = CIDSET_UNKNOWN;
   m_Coding = CIDCODING_UNKNOWN;
diff --git a/core/src/fpdfapi/fpdf_font/fpdf_font_cid_unittest.cpp b/core/src/fpdfapi/fpdf_font/fpdf_font_cid_unittest.cpp
new file mode 100644
index 0000000..0a8086a
--- /dev/null
+++ b/core/src/fpdfapi/fpdf_font/fpdf_font_cid_unittest.cpp
@@ -0,0 +1,66 @@
+// Copyright 2015 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "font_int.h"
+
+namespace {
+
+bool uint_ranges_equal(uint8_t* a, uint8_t* b, size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    if (a[i] != b[i])
+      return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+TEST(fpdf_font_cid, CMap_GetCode) {
+  EXPECT_EQ(0, CPDF_CMapParser::CMap_GetCode(""));
+  EXPECT_EQ(0, CPDF_CMapParser::CMap_GetCode("<"));
+  EXPECT_EQ(194, CPDF_CMapParser::CMap_GetCode("<c2"));
+  EXPECT_EQ(162, CPDF_CMapParser::CMap_GetCode("<A2"));
+  EXPECT_EQ(2802, CPDF_CMapParser::CMap_GetCode("<Af2"));
+  EXPECT_EQ(162, CPDF_CMapParser::CMap_GetCode("<A2z"));
+
+  EXPECT_EQ(12, CPDF_CMapParser::CMap_GetCode("12"));
+  EXPECT_EQ(12, CPDF_CMapParser::CMap_GetCode("12d"));
+  EXPECT_EQ(128, CPDF_CMapParser::CMap_GetCode("128"));
+}
+
+TEST(fpdf_font_cid, CMap_GetCodeRange) {
+  CMap_CodeRange range;
+
+  // Must start with a <
+  EXPECT_FALSE(CPDF_CMapParser::CMap_GetCodeRange(range, "", ""));
+  EXPECT_FALSE(CPDF_CMapParser::CMap_GetCodeRange(range, "A", ""));
+
+  // m_CharSize must be <= 4
+  EXPECT_FALSE(CPDF_CMapParser::CMap_GetCodeRange(range, "<aaaaaaaaaa>", ""));
+  EXPECT_EQ(5, range.m_CharSize);
+
+  EXPECT_TRUE(
+      CPDF_CMapParser::CMap_GetCodeRange(range, "<12345678>", "<87654321>"));
+  EXPECT_EQ(4, range.m_CharSize);
+  {
+    uint8_t lower[4] = {18, 52, 86, 120};
+    uint8_t upper[4] = {135, 101, 67, 33};
+    EXPECT_TRUE(uint_ranges_equal(lower, range.m_Lower, range.m_CharSize));
+    EXPECT_TRUE(uint_ranges_equal(upper, range.m_Upper, range.m_CharSize));
+  }
+
+  // Hex characters
+  EXPECT_TRUE(CPDF_CMapParser::CMap_GetCodeRange(range, "<a1>", "<F3>"));
+  EXPECT_EQ(1, range.m_CharSize);
+  EXPECT_EQ(161, range.m_Lower[0]);
+  EXPECT_EQ(243, range.m_Upper[0]);
+
+  // The second string should return 0's if it is shorter
+  EXPECT_TRUE(CPDF_CMapParser::CMap_GetCodeRange(range, "<a1>", ""));
+  EXPECT_EQ(1, range.m_CharSize);
+  EXPECT_EQ(161, range.m_Lower[0]);
+  EXPECT_EQ(0, range.m_Upper[0]);
+}
diff --git a/pdfium.gyp b/pdfium.gyp
index 4cab182..7c8c02e 100644
--- a/pdfium.gyp
+++ b/pdfium.gyp
@@ -714,6 +714,7 @@
         '<(DEPTH)'
       ],
       'sources': [
+        'core/src/fpdfapi/fpdf_font/fpdf_font_cid_unittest.cpp',
         'core/src/fpdfapi/fpdf_font/fpdf_font_unittest.cpp',
         'core/src/fpdfapi/fpdf_parser/fpdf_parser_decode_unittest.cpp',
         'core/src/fxcodec/codec/fx_codec_jpx_unittest.cpp',