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;