Avoid passing invalid keys to CPDF_Dictionary::SetFor().

Consolidate the logic for checking key validity into
CPDF_Dictionary::IsValidKey(), then use IsValidKey() in several places
that set dictionary keys.

Bug: chromium:1226299,chromium:1226364,chromium:1226365
Change-Id: I63d40edb11094a12fcf32ad51d9c62e5f272bd10
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/83050
Reviewed-by: Hui Yingst <nigi@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_streamcontentparser.cpp b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
index 6e1e3b2..75dc551 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -618,7 +618,7 @@
     auto word = m_pSyntax->GetWord();
     ByteString key(word.Last(word.GetLength() - 1));
     auto pObj = m_pSyntax->ReadNextObject(false, false, 0);
-    if (!key.IsEmpty()) {
+    if (CPDF_Dictionary::IsValidKey(key)) {
       if (pObj && !pObj->IsInline()) {
         pDict->SetNewFor<CPDF_Reference>(key, m_pDocument.Get(),
                                          pObj->GetObjNum());
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index da16168..4b5e1ca 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -334,7 +334,7 @@
       if (!pObj)
         return nullptr;
 
-      if (!key.IsEmpty())
+      if (CPDF_Dictionary::IsValidKey(key))
         pDict->SetFor(key, std::move(pObj));
     }
     return pDict;
diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp
index daeb765..0494372 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.cpp
+++ b/core/fpdfapi/parser/cpdf_dictionary.cpp
@@ -82,6 +82,11 @@
   return pCopy;
 }
 
+// static
+bool CPDF_Dictionary::IsValidKey(const ByteString& key) {
+  return !key.IsEmpty() && key.AsStringView().IsASCII();
+}
+
 const CPDF_Object* CPDF_Dictionary::GetObjectFor(const ByteString& key) const {
   auto it = m_Map.find(key);
   return it != m_Map.end() ? it->second.Get() : nullptr;
@@ -210,8 +215,7 @@
 
 CPDF_Object* CPDF_Dictionary::SetFor(const ByteString& key,
                                      RetainPtr<CPDF_Object> pObj) {
-  CHECK(!key.IsEmpty());
-  CHECK(key.AsStringView().IsASCII());
+  CHECK(IsValidKey(key));
   CHECK(!IsLocked());
   if (!pObj) {
     m_Map.erase(key);
diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h
index 715112b..ef545e8 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.h
+++ b/core/fpdfapi/parser/cpdf_dictionary.h
@@ -41,6 +41,9 @@
   bool WriteTo(IFX_ArchiveStream* archive,
                const CPDF_Encryptor* encryptor) const override;
 
+  // `key` must be non-empty and ASCII, per PDF 32000 standard, section 7.2.1.
+  static bool IsValidKey(const ByteString& key);
+
   bool IsLocked() const { return !!m_LockCount; }
 
   size_t size() const { return m_Map.size(); }
diff --git a/core/fpdfapi/parser/cpdf_syntax_parser.cpp b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
index 2560e98..6d837a3 100644
--- a/core/fpdfapi/parser/cpdf_syntax_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_syntax_parser.cpp
@@ -592,8 +592,7 @@
       // `key` has to be "/X" at the minimum.
       if (key.GetLength() > 1) {
         ByteString key_no_slash(key.raw_str() + 1, key.GetLength() - 1);
-        // `key_no_slash` must be ASCII, per PDF 32000 standard, section 7.2.1.
-        if (key_no_slash.AsStringView().IsASCII())
+        if (CPDF_Dictionary::IsValidKey(key_no_slash))
           pDict->SetFor(key_no_slash, std::move(pObj));
       }
     }
diff --git a/core/fpdfdoc/cpdf_generateap.cpp b/core/fpdfdoc/cpdf_generateap.cpp
index 488d504..29efe16 100644
--- a/core/fpdfdoc/cpdf_generateap.cpp
+++ b/core/fpdfdoc/cpdf_generateap.cpp
@@ -943,6 +943,9 @@
     return;
 
   ByteString font_name = font.value();
+  if (!CPDF_Dictionary::IsValidKey(font_name))
+    return;
+
   CFX_Color crText = fpdfdoc::CFXColorFromString(DA);
   CPDF_Dictionary* pDRDict = pFormDict->GetDictFor("DR");
   if (!pDRDict)