Reinstate CPDF_FormField DCHECKs and improve SetValue()
Undo a small portion of https://pdfium-review.googlesource.com/111552
so SetItemSelection() and IsItemSelected() get their DCHECKs back.
Instead, fix the issue by changing the caller to avoid tripping the
DCHECKs. As part of this work:
- Use CHECK instead of DCHECK, per modern coding guidelines.
- Add an IsComboOrListField() helper function and use that everywhere.
- Add a HasOptField() helper function and use that as an additional
guardrail to make sure CPDF_FormField only reads /Opt values when
appropriate.
- Update FPDFAnnot_IsOptionSelected() to avoid tripping over the /Opt
checks.
Bug: chromium:1477093
Change-Id: Id774393afcd8e976ffa7f2ae869ceac9c9680b06
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/111670
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp
index f4a62bd..bfcb797 100644
--- a/core/fpdfdoc/cpdf_formfield.cpp
+++ b/core/fpdfdoc/cpdf_formfield.cpp
@@ -50,6 +50,28 @@
nLevel + 1);
}
+bool IsComboOrListField(CPDF_FormField::Type type) {
+ switch (type) {
+ case CPDF_FormField::kComboBox:
+ case CPDF_FormField::kListBox:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool HasOptField(CPDF_FormField::Type type) {
+ switch (type) {
+ case CPDF_FormField::kCheckBox:
+ case CPDF_FormField::kRadioButton:
+ case CPDF_FormField::kComboBox:
+ case CPDF_FormField::kListBox:
+ return true;
+ default:
+ return false;
+ }
+}
+
} // namespace
// static
@@ -348,7 +370,7 @@
bool CPDF_FormField::SetValue(const WideString& value,
bool bDefault,
NotificationOption notify) {
- switch (m_Type) {
+ switch (GetType()) {
case kCheckBox:
case kRadioButton: {
SetCheckValue(value, bDefault, notify);
@@ -366,7 +388,13 @@
ByteString key(bDefault ? pdfium::form_fields::kDV
: pdfium::form_fields::kV);
m_pDict->SetNewFor<CPDF_String>(key, csValue.AsStringView());
- int iIndex = FindOption(csValue);
+
+ int iIndex;
+ if (GetType() == kComboBox) {
+ iIndex = FindOption(csValue);
+ } else {
+ iIndex = -1;
+ }
if (iIndex < 0) {
if (m_Type == kRichText && !bDefault) {
m_pDict->SetFor(pdfium::form_fields::kRV,
@@ -493,9 +521,7 @@
}
bool CPDF_FormField::IsItemSelected(int index) const {
- if (GetType() != kComboBox && GetType() != kListBox) {
- return false;
- }
+ CHECK(IsComboOrListField(GetType()));
if (index < 0 || index >= CountOptions()) {
return false;
}
@@ -505,9 +531,7 @@
}
bool CPDF_FormField::SetItemSelection(int index, NotificationOption notify) {
- if (GetType() != kComboBox && GetType() != kListBox) {
- return false;
- }
+ CHECK(IsComboOrListField(GetType()));
if (index < 0 || index >= CountOptions()) {
return false;
}
@@ -554,7 +578,7 @@
}
int CPDF_FormField::GetDefaultSelectedItem() const {
- DCHECK(GetType() == kComboBox || GetType() == kListBox);
+ CHECK(IsComboOrListField(GetType()));
RetainPtr<const CPDF_Object> pValue = GetDefaultValueObject();
if (!pValue)
return -1;
@@ -569,11 +593,13 @@
}
int CPDF_FormField::CountOptions() const {
+ CHECK(HasOptField(GetType()));
RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt"));
return pArray ? fxcrt::CollectionSize<int>(*pArray) : 0;
}
WideString CPDF_FormField::GetOptionText(int index, int sub_index) const {
+ CHECK(HasOptField(GetType()));
RetainPtr<const CPDF_Array> pArray = ToArray(GetFieldAttrInternal("Opt"));
if (!pArray)
return WideString();
@@ -776,7 +802,7 @@
}
bool CPDF_FormField::UseSelectedIndicesObject() const {
- DCHECK(GetType() == kComboBox || GetType() == kListBox);
+ CHECK(IsComboOrListField(GetType()));
RetainPtr<const CPDF_Object> pSelectedIndicesObject =
GetSelectedIndicesObject();
@@ -895,13 +921,13 @@
}
RetainPtr<const CPDF_Object> CPDF_FormField::GetSelectedIndicesObject() const {
- DCHECK(GetType() == kComboBox || GetType() == kListBox);
+ CHECK(IsComboOrListField(GetType()));
return GetFieldAttrInternal("I");
}
RetainPtr<const CPDF_Object> CPDF_FormField::GetValueOrSelectedIndicesObject()
const {
- DCHECK(GetType() == kComboBox || GetType() == kListBox);
+ CHECK(IsComboOrListField(GetType()));
RetainPtr<const CPDF_Object> pValue = GetValueObject();
return pValue ? pValue : GetSelectedIndicesObject();
}
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index cb7c96d..0cba33e 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -1300,19 +1300,22 @@
FPDFAnnot_IsOptionSelected(FPDF_FORMHANDLE handle,
FPDF_ANNOTATION annot,
int index) {
- if (index < 0)
+ if (index < 0) {
return false;
+ }
const CPDF_FormField* form_field = GetFormField(handle, annot);
- if (!form_field || index >= form_field->CountOptions())
+ if (!form_field) {
return false;
+ }
if (form_field->GetFieldType() != FormFieldType::kComboBox &&
form_field->GetFieldType() != FormFieldType::kListBox) {
return false;
}
- return form_field->IsItemSelected(index);
+ return index < form_field->CountOptions() &&
+ form_field->IsItemSelected(index);
}
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV