Fix timeout in pdf_cpdf_tounicodemap_fuzzer

Iterating through a range of multimap to check for duplicate
cid-unicode mappings can be too time consuming and cause timeout in
CPDF_ToUnicodeMap::InsertIntoMultimap(). This CL changes `m_Multimap`
into std::map<uint32_t, std::set<uint32_t>> so that no duplicate
unicode can be inserted into the set by default and the insertion can
be done more efficiently to avoid timeout.

Bug: chromium:1347025
Change-Id: I54bdf4cc2d34f1dd0c0f18d82c9b3a7941833269
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/95791
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Nigi <nigi@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_tounicodemap.cpp b/core/fpdfapi/font/cpdf_tounicodemap.cpp
index 00714f1..349783c 100644
--- a/core/fpdfapi/font/cpdf_tounicodemap.cpp
+++ b/core/fpdfapi/font/cpdf_tounicodemap.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfapi/font/cpdf_tounicodemap.h"
 
 #include <map>
+#include <set>
 #include <utility>
 
 #include "core/fpdfapi/font/cpdf_cid2unicodemap.h"
@@ -54,7 +55,7 @@
         m_pBaseMap->UnicodeFromCID(static_cast<uint16_t>(charcode)));
   }
 
-  uint32_t value = it->second;
+  uint32_t value = *it->second.begin();
   wchar_t unicode = static_cast<wchar_t>(value & 0xffff);
   if (unicode != 0xffff)
     return WideString(unicode);
@@ -65,12 +66,18 @@
 
 uint32_t CPDF_ToUnicodeMap::ReverseLookup(wchar_t unicode) const {
   for (const auto& pair : m_Multimap) {
-    if (pair.second == static_cast<uint32_t>(unicode))
+    if (pdfium::Contains(pair.second, static_cast<uint32_t>(unicode)))
       return pair.first;
   }
   return 0;
 }
 
+size_t CPDF_ToUnicodeMap::GetUnicodeCountByCharcodeForTesting(
+    uint32_t charcode) const {
+  auto it = m_Multimap.find(charcode);
+  return it != m_Multimap.end() ? it->second.size() : 0u;
+}
+
 // static
 absl::optional<uint32_t> CPDF_ToUnicodeMap::StringToCode(ByteStringView str) {
   size_t len = str.GetLength();
@@ -228,18 +235,11 @@
 }
 
 void CPDF_ToUnicodeMap::InsertIntoMultimap(uint32_t code, uint32_t destcode) {
-  if (!pdfium::Contains(m_Multimap, code)) {
-    m_Multimap.emplace(code, destcode);
+  auto it = m_Multimap.find(code);
+  if (it == m_Multimap.end()) {
+    m_Multimap.emplace(code, std::set<uint32_t>{destcode});
     return;
   }
 
-  auto ret = m_Multimap.equal_range(code);
-  for (auto iter = ret.first; iter != ret.second; ++iter) {
-    if (iter->second == destcode) {
-      // Do not insert since a duplicate mapping is found.
-      return;
-    }
-  }
-
-  m_Multimap.emplace(code, destcode);
+  it->second.emplace(destcode);
 }
diff --git a/core/fpdfapi/font/cpdf_tounicodemap.h b/core/fpdfapi/font/cpdf_tounicodemap.h
index 61d0ac6..7935ede 100644
--- a/core/fpdfapi/font/cpdf_tounicodemap.h
+++ b/core/fpdfapi/font/cpdf_tounicodemap.h
@@ -8,6 +8,7 @@
 #define CORE_FPDFAPI_FONT_CPDF_TOUNICODEMAP_H_
 
 #include <map>
+#include <set>
 #include <vector>
 
 #include "core/fxcrt/fx_string.h"
@@ -26,7 +27,7 @@
   WideString Lookup(uint32_t charcode) const;
   uint32_t ReverseLookup(wchar_t unicode) const;
 
-  size_t GetMultimapSizeForTesting() const { return m_Multimap.size(); }
+  size_t GetUnicodeCountByCharcodeForTesting(uint32_t cid) const;
 
  private:
   friend class cpdf_tounicodemap_StringToCode_Test;
@@ -45,7 +46,7 @@
   // before.
   void InsertIntoMultimap(uint32_t code, uint32_t destcode);
 
-  std::multimap<uint32_t, uint32_t> m_Multimap;
+  std::map<uint32_t, std::set<uint32_t>> m_Multimap;
   UnownedPtr<const CPDF_CID2UnicodeMap> m_pBaseMap;
   std::vector<WideString> m_MultiCharVec;
 };
diff --git a/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp b/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp
index 098983c..74eaa3b 100644
--- a/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp
+++ b/core/fpdfapi/font/cpdf_tounicodemap_unittest.cpp
@@ -90,7 +90,8 @@
     CPDF_ToUnicodeMap map(stream.Get());
     EXPECT_EQ(1u, map.ReverseLookup(0x0041));
     EXPECT_EQ(2u, map.ReverseLookup(0x0042));
-    EXPECT_EQ(2u, map.GetMultimapSizeForTesting());
+    EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(1u));
+    EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(2u));
   }
   {
     // The same CID with different unicodes.
@@ -101,7 +102,7 @@
     CPDF_ToUnicodeMap map(stream.Get());
     EXPECT_EQ(0u, map.ReverseLookup(0x0041));
     EXPECT_EQ(0u, map.ReverseLookup(0x0042));
-    EXPECT_EQ(2u, map.GetMultimapSizeForTesting());
+    EXPECT_EQ(2u, map.GetUnicodeCountByCharcodeForTesting(0u));
   }
   {
     // Duplicate mappings of CID 0 to unicode "A". There should be only 1 entry
@@ -113,6 +114,6 @@
     stream->SetData(pdfium::make_span(kInput3));
     CPDF_ToUnicodeMap map(stream.Get());
     EXPECT_EQ(0u, map.ReverseLookup(0x0041));
-    EXPECT_EQ(1u, map.GetMultimapSizeForTesting());
+    EXPECT_EQ(1u, map.GetUnicodeCountByCharcodeForTesting(0u));
   }
 }