Change CPDF_CMapParser::GetCodeRange() to return Optional.

Also make the method private/static and friend its unit test instead.
Also make GetCode() private/static and friend its unit test instead.

Change-Id: Ic3e020f826e0bd711e3b5b7cd317f57784c83900
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/59510
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_cmapparser.cpp b/core/fpdfapi/font/cpdf_cmapparser.cpp
index 1f7c0bc..56efae7 100644
--- a/core/fpdfapi/font/cpdf_cmapparser.cpp
+++ b/core/fpdfapi/font/cpdf_cmapparser.cpp
@@ -116,9 +116,10 @@
         return;
 
       if (m_CodeSeq % 2) {
-        CPDF_CMap::CodeRange range;
-        if (GetCodeRange(range, m_LastWord.AsStringView(), word))
-          m_PendingRanges.push_back(range);
+        Optional<CPDF_CMap::CodeRange> range =
+            GetCodeRange(m_LastWord.AsStringView(), word);
+        if (range.has_value())
+          m_PendingRanges.push_back(range.value());
       }
       m_CodeSeq++;
     }
@@ -126,7 +127,8 @@
   m_LastWord = word;
 }
 
-uint32_t CPDF_CMapParser::GetCode(ByteStringView word) const {
+// static
+uint32_t CPDF_CMapParser::GetCode(ByteStringView word) {
   if (word.IsEmpty())
     return 0;
 
@@ -148,21 +150,24 @@
   return num.ValueOrDie();
 }
 
-bool CPDF_CMapParser::GetCodeRange(CPDF_CMap::CodeRange& range,
-                                   ByteStringView first,
-                                   ByteStringView second) const {
+// static
+Optional<CPDF_CMap::CodeRange> CPDF_CMapParser::GetCodeRange(
+    ByteStringView first,
+    ByteStringView second) {
   if (first.GetLength() == 0 || first[0] != '<')
-    return false;
+    return pdfium::nullopt;
 
   size_t i;
   for (i = 1; i < first.GetLength(); ++i) {
     if (first[i] == '>')
       break;
   }
-  range.m_CharSize = (i - 1) / 2;
-  if (range.m_CharSize > 4)
-    return false;
+  size_t char_size = (i - 1) / 2;
+  if (char_size > 4)
+    return pdfium::nullopt;
 
+  CPDF_CMap::CodeRange range;
+  range.m_CharSize = char_size;
   for (i = 0; i < range.m_CharSize; ++i) {
     uint8_t digit1 = first[i * 2 + 1];
     uint8_t digit2 = first[i * 2 + 2];
@@ -179,7 +184,7 @@
     range.m_Upper[i] =
         FXSYS_HexCharToInt(digit1) * 16 + FXSYS_HexCharToInt(digit2);
   }
-  return true;
+  return range;
 }
 
 // static
diff --git a/core/fpdfapi/font/cpdf_cmapparser.h b/core/fpdfapi/font/cpdf_cmapparser.h
index 5c8db40..e8ea29b 100644
--- a/core/fpdfapi/font/cpdf_cmapparser.h
+++ b/core/fpdfapi/font/cpdf_cmapparser.h
@@ -13,6 +13,7 @@
 #include "core/fpdfapi/font/cpdf_cidfont.h"
 #include "core/fpdfapi/font/cpdf_cmap.h"
 #include "core/fxcrt/unowned_ptr.h"
+#include "third_party/base/optional.h"
 
 class CPDF_CMapParser {
  public:
@@ -27,14 +28,12 @@
     return std::move(m_AdditionalCharcodeToCIDMappings);
   }
 
-  uint32_t GetCode(ByteStringView word) const;
-  bool GetCodeRange(CPDF_CMap::CodeRange& range,
-                    ByteStringView first,
-                    ByteStringView second) const;
-
   static CIDSet CharsetFromOrdering(ByteStringView ordering);
 
  private:
+  friend class cpdf_cmapparser_GetCode_Test;
+  friend class cpdf_cmapparser_GetCodeRange_Test;
+
   enum Status {
     kStart,
     kProcessingCidChar,
@@ -46,6 +45,10 @@
     kProcessingCodeSpaceRange,
   };
 
+  static uint32_t GetCode(ByteStringView word);
+  static Optional<CPDF_CMap::CodeRange> GetCodeRange(ByteStringView first,
+                                                     ByteStringView second);
+
   Status m_Status = kStart;
   int m_CodeSeq = 0;
   UnownedPtr<CPDF_CMap> const m_pCMap;
diff --git a/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp b/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp
index 1a36eb7..da654f3 100644
--- a/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp
+++ b/core/fpdfapi/font/cpdf_cmapparser_unittest.cpp
@@ -8,7 +8,7 @@
 
 namespace {
 
-bool uint_ranges_equal(uint8_t* a, uint8_t* b, size_t count) {
+bool uint_ranges_equal(const uint8_t* a, const uint8_t* b, size_t count) {
   for (size_t i = 0; i < count; ++i) {
     if (a[i] != b[i])
       return false;
@@ -19,55 +19,57 @@
 }  // namespace
 
 TEST(cpdf_cmapparser, GetCode) {
-  CPDF_CMapParser parser(nullptr);
+  EXPECT_EQ(0u, CPDF_CMapParser::GetCode(""));
+  EXPECT_EQ(0u, CPDF_CMapParser::GetCode("<"));
+  EXPECT_EQ(194u, CPDF_CMapParser::GetCode("<c2"));
+  EXPECT_EQ(162u, CPDF_CMapParser::GetCode("<A2"));
+  EXPECT_EQ(2802u, CPDF_CMapParser::GetCode("<Af2"));
+  EXPECT_EQ(162u, CPDF_CMapParser::GetCode("<A2z"));
 
-  EXPECT_EQ(0u, parser.GetCode(""));
-  EXPECT_EQ(0u, parser.GetCode("<"));
-  EXPECT_EQ(194u, parser.GetCode("<c2"));
-  EXPECT_EQ(162u, parser.GetCode("<A2"));
-  EXPECT_EQ(2802u, parser.GetCode("<Af2"));
-  EXPECT_EQ(162u, parser.GetCode("<A2z"));
+  EXPECT_EQ(12u, CPDF_CMapParser::GetCode("12"));
+  EXPECT_EQ(12u, CPDF_CMapParser::GetCode("12d"));
+  EXPECT_EQ(128u, CPDF_CMapParser::GetCode("128"));
 
-  EXPECT_EQ(12u, parser.GetCode("12"));
-  EXPECT_EQ(12u, parser.GetCode("12d"));
-  EXPECT_EQ(128u, parser.GetCode("128"));
-
-  EXPECT_EQ(4294967295u, parser.GetCode("<FFFFFFFF"));
+  EXPECT_EQ(4294967295u, CPDF_CMapParser::GetCode("<FFFFFFFF"));
 
   // Overflow a uint32_t.
-  EXPECT_EQ(0u, parser.GetCode("<100000000"));
+  EXPECT_EQ(0u, CPDF_CMapParser::GetCode("<100000000"));
 }
 
 TEST(cpdf_cmapparser, GetCodeRange) {
-  CPDF_CMapParser parser(nullptr);
-  CPDF_CMap::CodeRange range;
+  Optional<CPDF_CMap::CodeRange> range;
 
   // Must start with a <
-  EXPECT_FALSE(parser.GetCodeRange(range, "", ""));
-  EXPECT_FALSE(parser.GetCodeRange(range, "A", ""));
+  range = CPDF_CMapParser::GetCodeRange("", "");
+  EXPECT_FALSE(range.has_value());
+  range = CPDF_CMapParser::GetCodeRange("A", "");
+  EXPECT_FALSE(range.has_value());
 
   // m_CharSize must be <= 4
-  EXPECT_FALSE(parser.GetCodeRange(range, "<aaaaaaaaaa>", ""));
-  EXPECT_EQ(5u, range.m_CharSize);
+  range = CPDF_CMapParser::GetCodeRange("<aaaaaaaaaa>", "");
+  EXPECT_FALSE(range.has_value());
 
-  EXPECT_TRUE(parser.GetCodeRange(range, "<12345678>", "<87654321>"));
-  EXPECT_EQ(4u, range.m_CharSize);
+  range = CPDF_CMapParser::GetCodeRange("<12345678>", "<87654321>");
+  ASSERT_TRUE(range.has_value());
+  ASSERT_EQ(4u, range.value().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));
+    constexpr uint8_t kLower[4] = {18, 52, 86, 120};
+    constexpr uint8_t kUpper[4] = {135, 101, 67, 33};
+    EXPECT_TRUE(uint_ranges_equal(kLower, range.value().m_Lower, 4));
+    EXPECT_TRUE(uint_ranges_equal(kUpper, range.value().m_Upper, 4));
   }
 
   // Hex characters
-  EXPECT_TRUE(parser.GetCodeRange(range, "<a1>", "<F3>"));
-  EXPECT_EQ(1u, range.m_CharSize);
-  EXPECT_EQ(161, range.m_Lower[0]);
-  EXPECT_EQ(243, range.m_Upper[0]);
+  range = CPDF_CMapParser::GetCodeRange("<a1>", "<F3>");
+  ASSERT_TRUE(range.has_value());
+  ASSERT_EQ(1u, range.value().m_CharSize);
+  EXPECT_EQ(161, range.value().m_Lower[0]);
+  EXPECT_EQ(243, range.value().m_Upper[0]);
 
   // The second string should return 0's if it is shorter
-  EXPECT_TRUE(parser.GetCodeRange(range, "<a1>", ""));
-  EXPECT_EQ(1u, range.m_CharSize);
-  EXPECT_EQ(161, range.m_Lower[0]);
-  EXPECT_EQ(0, range.m_Upper[0]);
+  range = CPDF_CMapParser::GetCodeRange("<a1>", "");
+  ASSERT_TRUE(range.has_value());
+  ASSERT_EQ(1u, range.value().m_CharSize);
+  EXPECT_EQ(161, range.value().m_Lower[0]);
+  EXPECT_EQ(0, range.value().m_Upper[0]);
 }