Fix nits in stream parsing code.

- Use CalculatePitch8() in CPDF_StreamParser::ReadInlineStream().
- Add CPDF_StreamParser::WordBufferMatches() and constants.
- Reflow ReplaceAbbr().
- Make more pointers const.
- Fix some variable names.

Change-Id: I8fb7763aad57355754e41f69af0328a43dde1fd4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/51830
Reviewed-by: Tom Sepez <tsepez@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 a714219..8908228 100644
--- a/core/fpdfapi/page/cpdf_streamcontentparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamcontentparser.cpp
@@ -141,13 +141,13 @@
   const char* full_name;
 };
 
-const AbbrPair InlineKeyAbbr[] = {
+const AbbrPair kInlineKeyAbbr[] = {
     {"BPC", "BitsPerComponent"}, {"CS", "ColorSpace"}, {"D", "Decode"},
     {"DP", "DecodeParms"},       {"F", "Filter"},      {"H", "Height"},
     {"IM", "ImageMask"},         {"I", "Interpolate"}, {"W", "Width"},
 };
 
-const AbbrPair InlineValueAbbr[] = {
+const AbbrPair kInlineValueAbbr[] = {
     {"G", "DeviceGray"},       {"RGB", "DeviceRGB"},
     {"CMYK", "DeviceCMYK"},    {"I", "Indexed"},
     {"AHx", "ASCIIHexDecode"}, {"A85", "ASCII85Decode"},
@@ -171,72 +171,77 @@
   return it != table + count ? ByteStringView(it->full_name) : ByteStringView();
 }
 
-void ReplaceAbbr(CPDF_Object* pObj) {
-  switch (pObj->GetType()) {
-    case CPDF_Object::kDictionary: {
-      std::vector<AbbrReplacementOp> replacements;
-      CPDF_Dictionary* pDict = pObj->AsDictionary();
-      {
-        CPDF_DictionaryLocker locker(pDict);
-        for (const auto& it : locker) {
-          ByteString key = it.first;
-          CPDF_Object* value = it.second.get();
-          ByteStringView fullname = FindFullName(
-              InlineKeyAbbr, FX_ArraySize(InlineKeyAbbr), key.AsStringView());
-          if (!fullname.IsEmpty()) {
-            AbbrReplacementOp op;
-            op.is_replace_key = true;
-            op.key = std::move(key);
-            op.replacement = fullname;
-            replacements.push_back(op);
-            key = fullname;
-          }
+void ReplaceAbbr(CPDF_Object* pObj);
 
-          if (value->IsName()) {
-            ByteString name = value->GetString();
-            fullname =
-                FindFullName(InlineValueAbbr, FX_ArraySize(InlineValueAbbr),
-                             name.AsStringView());
-            if (!fullname.IsEmpty()) {
-              AbbrReplacementOp op;
-              op.is_replace_key = false;
-              op.key = key;
-              op.replacement = fullname;
-              replacements.push_back(op);
-            }
-          } else {
-            ReplaceAbbr(value);
-          }
+void ReplaceAbbrInDictionary(CPDF_Dictionary* pDict) {
+  std::vector<AbbrReplacementOp> replacements;
+  {
+    CPDF_DictionaryLocker locker(pDict);
+    for (const auto& it : locker) {
+      ByteString key = it.first;
+      CPDF_Object* value = it.second.get();
+      ByteStringView fullname = FindFullName(
+          kInlineKeyAbbr, FX_ArraySize(kInlineKeyAbbr), key.AsStringView());
+      if (!fullname.IsEmpty()) {
+        AbbrReplacementOp op;
+        op.is_replace_key = true;
+        op.key = std::move(key);
+        op.replacement = fullname;
+        replacements.push_back(op);
+        key = fullname;
+      }
+
+      if (value->IsName()) {
+        ByteString name = value->GetString();
+        fullname =
+            FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr),
+                         name.AsStringView());
+        if (!fullname.IsEmpty()) {
+          AbbrReplacementOp op;
+          op.is_replace_key = false;
+          op.key = key;
+          op.replacement = fullname;
+          replacements.push_back(op);
         }
+      } else {
+        ReplaceAbbr(value);
       }
-      for (const auto& op : replacements) {
-        if (op.is_replace_key)
-          pDict->ReplaceKey(op.key, ByteString(op.replacement));
-        else
-          pDict->SetNewFor<CPDF_Name>(op.key, ByteString(op.replacement));
-      }
-      break;
     }
-    case CPDF_Object::kArray: {
-      CPDF_Array* pArray = pObj->AsArray();
-      for (size_t i = 0; i < pArray->size(); i++) {
-        CPDF_Object* pElement = pArray->GetObjectAt(i);
-        if (pElement->IsName()) {
-          ByteString name = pElement->GetString();
-          ByteStringView fullname =
-              FindFullName(InlineValueAbbr, FX_ArraySize(InlineValueAbbr),
-                           name.AsStringView());
-          if (!fullname.IsEmpty())
-            pArray->SetNewAt<CPDF_Name>(i, ByteString(fullname));
-        } else {
-          ReplaceAbbr(pElement);
-        }
-      }
-      break;
-    }
-    default:
-      break;
   }
+  for (const auto& op : replacements) {
+    if (op.is_replace_key)
+      pDict->ReplaceKey(op.key, ByteString(op.replacement));
+    else
+      pDict->SetNewFor<CPDF_Name>(op.key, ByteString(op.replacement));
+  }
+}
+
+void ReplaceAbbrInArray(CPDF_Array* pArray) {
+  for (size_t i = 0; i < pArray->size(); ++i) {
+    CPDF_Object* pElement = pArray->GetObjectAt(i);
+    if (pElement->IsName()) {
+      ByteString name = pElement->GetString();
+      ByteStringView fullname =
+          FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr),
+                       name.AsStringView());
+      if (!fullname.IsEmpty())
+        pArray->SetNewAt<CPDF_Name>(i, ByteString(fullname));
+    } else {
+      ReplaceAbbr(pElement);
+    }
+  }
+}
+
+void ReplaceAbbr(CPDF_Object* pObj) {
+  CPDF_Dictionary* pDict = pObj->AsDictionary();
+  if (pDict) {
+    ReplaceAbbrInDictionary(pDict);
+    return;
+  }
+
+  CPDF_Array* pArray = pObj->AsArray();
+  if (pArray)
+    ReplaceAbbrInArray(pArray);
 }
 
 }  // namespace
@@ -1622,13 +1627,13 @@
 // static
 ByteStringView CPDF_StreamContentParser::FindKeyAbbreviationForTesting(
     ByteStringView abbr) {
-  return FindFullName(InlineKeyAbbr, FX_ArraySize(InlineKeyAbbr), abbr);
+  return FindFullName(kInlineKeyAbbr, FX_ArraySize(kInlineKeyAbbr), abbr);
 }
 
 // static
 ByteStringView CPDF_StreamContentParser::FindValueAbbreviationForTesting(
     ByteStringView abbr) {
-  return FindFullName(InlineValueAbbr, FX_ArraySize(InlineValueAbbr), abbr);
+  return FindFullName(kInlineValueAbbr, FX_ArraySize(kInlineValueAbbr), abbr);
 }
 
 CPDF_StreamContentParser::ContentParam::ContentParam() {}
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index e579256..18c539a 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -38,6 +38,10 @@
 const uint32_t kMaxNestedParsingLevel = 512;
 const size_t kMaxStringLength = 32767;
 
+const char kTrue[] = "true";
+const char kFalse[] = "false";
+const char kNull[] = "null";
+
 uint32_t DecodeAllScanlines(std::unique_ptr<CCodec_ScanlineDecoder> pDecoder) {
   if (!pDecoder)
     return FX_INVALID_OFFSET;
@@ -65,7 +69,7 @@
                             int width,
                             int height,
                             const ByteString& decoder,
-                            CPDF_Dictionary* pParam,
+                            const CPDF_Dictionary* pParam,
                             uint32_t orig_size) {
   std::unique_ptr<uint8_t, FxFreeDeleter> ignored_result;
   uint32_t ignored_size;
@@ -121,26 +125,28 @@
   if (m_Pos == m_pBuf.size())
     return nullptr;
 
-  ByteString Decoder;
-  CPDF_Dictionary* pParam = nullptr;
+  ByteString decoder;
+  const CPDF_Dictionary* pParam = nullptr;
   CPDF_Object* pFilter = pDict->GetDirectObjectFor("Filter");
   if (pFilter) {
-    if (CPDF_Array* pArray = pFilter->AsArray()) {
-      Decoder = pArray->GetStringAt(0);
-      CPDF_Array* pParams = pDict->GetArrayFor(pdfium::stream::kDecodeParms);
+    const CPDF_Array* pArray = pFilter->AsArray();
+    if (pArray) {
+      decoder = pArray->GetStringAt(0);
+      const CPDF_Array* pParams =
+          pDict->GetArrayFor(pdfium::stream::kDecodeParms);
       if (pParams)
         pParam = pParams->GetDictAt(0);
     } else {
-      Decoder = pFilter->GetString();
+      decoder = pFilter->GetString();
       pParam = pDict->GetDictFor(pdfium::stream::kDecodeParms);
     }
   }
   uint32_t width = pDict->GetIntegerFor("Width");
   uint32_t height = pDict->GetIntegerFor("Height");
-  uint32_t OrigSize = 0;
+  uint32_t bpc = 1;
+  uint32_t nComponents = 1;
   if (pCSObj) {
-    uint32_t bpc = pDict->GetIntegerFor("BitsPerComponent");
-    uint32_t nComponents = 1;
+    bpc = pDict->GetIntegerFor("BitsPerComponent");
     CPDF_ColorSpace* pCS = pDoc->LoadColorSpace(pCSObj, nullptr);
     if (pCS) {
       nComponents = pCS->CountComponents();
@@ -148,44 +154,25 @@
     } else {
       nComponents = 3;
     }
-    uint32_t pitch = width;
-    if (bpc && pitch > INT_MAX / bpc)
-      return nullptr;
-
-    pitch *= bpc;
-    if (nComponents && pitch > INT_MAX / nComponents)
-      return nullptr;
-
-    pitch *= nComponents;
-    if (pitch > INT_MAX - 7)
-      return nullptr;
-
-    pitch += 7;
-    pitch /= 8;
-    OrigSize = pitch;
-  } else {
-    if (width > INT_MAX - 7)
-      return nullptr;
-
-    OrigSize = ((width + 7) / 8);
   }
-  if (height && OrigSize > INT_MAX / height)
+  FX_SAFE_UINT32 size = CalculatePitch8(bpc, nComponents, width);
+  size *= height;
+  if (!size.IsValid())
     return nullptr;
 
-  OrigSize *= height;
+  uint32_t dwOrigSize = size.ValueOrDie();
   std::unique_ptr<uint8_t, FxFreeDeleter> pData;
   uint32_t dwStreamSize;
-  if (Decoder.IsEmpty()) {
-    if (OrigSize > m_pBuf.size() - m_Pos)
-      OrigSize = m_pBuf.size() - m_Pos;
-    pData.reset(FX_Alloc(uint8_t, OrigSize));
-    auto copy_span = m_pBuf.subspan(m_Pos, OrigSize);
+  if (decoder.IsEmpty()) {
+    dwOrigSize = std::min<uint32_t>(dwOrigSize, m_pBuf.size() - m_Pos);
+    pData.reset(FX_Alloc(uint8_t, dwOrigSize));
+    auto copy_span = m_pBuf.subspan(m_Pos, dwOrigSize);
     memcpy(pData.get(), copy_span.data(), copy_span.size());
-    dwStreamSize = OrigSize;
-    m_Pos += OrigSize;
+    dwStreamSize = dwOrigSize;
+    m_Pos += dwOrigSize;
   } else {
     dwStreamSize = DecodeInlineStream(m_pBuf.subspan(m_Pos), width, height,
-                                      Decoder, pParam, OrigSize);
+                                      decoder, pParam, dwOrigSize);
     if (static_cast<int>(dwStreamSize) < 0)
       return nullptr;
 
@@ -279,16 +266,16 @@
     return Name;
 
   if (m_WordSize == 4) {
-    if (memcmp(m_WordBuffer, "true", 4) == 0) {
+    if (WordBufferMatches(kTrue)) {
       m_pLastObj = pdfium::MakeUnique<CPDF_Boolean>(true);
       return Others;
     }
-    if (memcmp(m_WordBuffer, "null", 4) == 0) {
+    if (WordBufferMatches(kNull)) {
       m_pLastObj = pdfium::MakeUnique<CPDF_Null>();
       return Others;
     }
   } else if (m_WordSize == 5) {
-    if (memcmp(m_WordBuffer, "false", 5) == 0) {
+    if (WordBufferMatches(kFalse)) {
       m_pLastObj = pdfium::MakeUnique<CPDF_Boolean>(false);
       return Others;
     }
@@ -368,16 +355,12 @@
     return std::move(pArray);
   }
 
-  if (m_WordSize == 5 && !memcmp(m_WordBuffer, "false", 5))
+  if (WordBufferMatches(kFalse))
     return pdfium::MakeUnique<CPDF_Boolean>(false);
-
-  if (m_WordSize == 4) {
-    if (memcmp(m_WordBuffer, "true", 4) == 0)
-      return pdfium::MakeUnique<CPDF_Boolean>(true);
-    if (memcmp(m_WordBuffer, "null", 4) == 0)
-      return pdfium::MakeUnique<CPDF_Null>();
-  }
-
+  if (WordBufferMatches(kTrue))
+    return pdfium::MakeUnique<CPDF_Boolean>(true);
+  if (WordBufferMatches(kNull))
+    return pdfium::MakeUnique<CPDF_Null>();
   return nullptr;
 }
 
@@ -603,3 +586,8 @@
 bool CPDF_StreamParser::PositionIsInBounds() const {
   return m_Pos < m_pBuf.size();
 }
+
+bool CPDF_StreamParser::WordBufferMatches(const char* pWord) const {
+  const size_t iLength = strlen(pWord);
+  return m_WordSize == iLength && memcmp(m_WordBuffer, pWord, iLength) == 0;
+}
diff --git a/core/fpdfapi/page/cpdf_streamparser.h b/core/fpdfapi/page/cpdf_streamparser.h
index d6c80f2..9c4ae49 100644
--- a/core/fpdfapi/page/cpdf_streamparser.h
+++ b/core/fpdfapi/page/cpdf_streamparser.h
@@ -51,9 +51,10 @@
   ByteString ReadString();
   ByteString ReadHexString();
   bool PositionIsInBounds() const;
+  bool WordBufferMatches(const char* pWord) const;
 
-  uint32_t m_Pos = 0;       // Current byte position within m_pBuf.
-  uint32_t m_WordSize = 0;  // Current byte position within m_WordBuffer.
+  uint32_t m_Pos = 0;       // Current byte position within |m_pBuf|.
+  uint32_t m_WordSize = 0;  // Current byte position within |m_WordBuffer|.
   WeakPtr<ByteStringPool> m_pPool;
   std::unique_ptr<CPDF_Object> m_pLastObj;
   pdfium::span<const uint8_t> m_pBuf;