Remove the ability to create an uninitialized CPDF_Stream
Change callers to properly initialize CPDF_Stream, instead of creating
an uninitialized one and then fixing it up.
Change-Id: I474fd264b95d717c257a702d65f6c10c704d9f55
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/115691
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
index a45c111..c558250 100644
--- a/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_walker_unittest.cpp
@@ -59,7 +59,9 @@
EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Array>()), "Arr");
EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_String>()), "Str");
EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Boolean>()), "Bool");
- EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Stream>()), "Stream");
+ EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Stream>(
+ pdfium::MakeRetain<CPDF_Dictionary>())),
+ "Stream Dict Num");
EXPECT_EQ(Walk(pdfium::MakeRetain<CPDF_Reference>(nullptr, 0)), "Ref");
}
diff --git a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
index 68fbbe7..040d6e6 100644
--- a/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_seekablemultistream_unittest.cpp
@@ -24,7 +24,9 @@
TEST(CXFAFileReadTest, EmptyStreams) {
std::vector<RetainPtr<const CPDF_Stream>> streams;
- streams.push_back(pdfium::MakeRetain<CPDF_Stream>());
+ streams.push_back(
+ pdfium::MakeRetain<CPDF_Stream>(pdfium::MakeRetain<CPDF_Dictionary>()));
+
auto fileread =
pdfium::MakeRetain<CPDF_SeekableMultiStream>(std::move(streams));
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index 6b2338b..acda825 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -36,8 +36,6 @@
} // namespace
-CPDF_Stream::CPDF_Stream() = default;
-
CPDF_Stream::CPDF_Stream(RetainPtr<CPDF_Dictionary> dict)
: CPDF_Stream(DataVector<uint8_t>(), std::move(dict)) {}
@@ -202,10 +200,7 @@
return pdfium::base::checked_cast<size_t>(
absl::get<RetainPtr<IFX_SeekableReadStream>>(data_)->GetSize());
}
- if (IsMemoryBased())
- return absl::get<DataVector<uint8_t>>(data_).size();
- DCHECK(IsUninitialized());
- return 0;
+ return absl::get<DataVector<uint8_t>>(data_).size();
}
pdfium::span<const uint8_t> CPDF_Stream::GetInMemoryRawData() const {
diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h
index 2efb9b2..08b72ed 100644
--- a/core/fpdfapi/parser/cpdf_stream.h
+++ b/core/fpdfapi/parser/cpdf_stream.h
@@ -56,9 +56,6 @@
// Can only be called when a stream is not memory-based.
DataVector<uint8_t> ReadAllRawData() const;
- bool IsUninitialized() const {
- return absl::holds_alternative<absl::monostate>(data_);
- }
bool IsFileBased() const {
return absl::holds_alternative<RetainPtr<IFX_SeekableReadStream>>(data_);
}
@@ -70,9 +67,6 @@
private:
friend class CPDF_Dictionary;
- // Uninitialized.
- CPDF_Stream();
-
// Initializes with empty data and /Length set to 0 in `dict`.
// If `dict` is null, then a new dictionary will be created instead.
explicit CPDF_Stream(RetainPtr<CPDF_Dictionary> dict);
@@ -99,10 +93,7 @@
void SetLengthInDict(int length);
- absl::variant<absl::monostate,
- RetainPtr<IFX_SeekableReadStream>,
- DataVector<uint8_t>>
- data_;
+ absl::variant<RetainPtr<IFX_SeekableReadStream>, DataVector<uint8_t>> data_;
RetainPtr<CPDF_Dictionary> dict_;
};
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp
index 4f42c6d..e3c14af 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.cpp
+++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -99,9 +99,6 @@
}
void CPDF_StreamAcc::ProcessRawData() {
- if (m_pStream->IsUninitialized())
- return;
-
uint32_t dwSrcSize = m_pStream->GetRawSize();
if (dwSrcSize == 0)
return;
@@ -120,9 +117,6 @@
void CPDF_StreamAcc::ProcessFilteredData(uint32_t estimated_size,
bool bImageAcc) {
- if (m_pStream->IsUninitialized())
- return;
-
uint32_t dwSrcSize = m_pStream->GetRawSize();
if (dwSrcSize == 0)
return;
diff --git a/core/fpdfdoc/cpdf_generateap.cpp b/core/fpdfdoc/cpdf_generateap.cpp
index e7f7256..b6a24fd 100644
--- a/core/fpdfdoc/cpdf_generateap.cpp
+++ b/core/fpdfdoc/cpdf_generateap.cpp
@@ -501,29 +501,29 @@
return pResourceDict;
}
-void GenerateAndSetAPDict(CPDF_Document* pDoc,
- CPDF_Dictionary* pAnnotDict,
- fxcrt::ostringstream* psAppStream,
- RetainPtr<CPDF_Dictionary> pResourceDict,
- bool bIsTextMarkupAnnotation) {
- auto pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
- pNormalStream->SetDataFromStringstream(psAppStream);
+void GenerateAndSetAPDict(CPDF_Document* doc,
+ CPDF_Dictionary* annot_dict,
+ fxcrt::ostringstream* app_stream,
+ RetainPtr<CPDF_Dictionary> resource_dict,
+ bool is_text_markup_annotation) {
+ auto stream_dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ stream_dict->SetNewFor<CPDF_Number>("FormType", 1);
+ stream_dict->SetNewFor<CPDF_Name>("Type", "XObject");
+ stream_dict->SetNewFor<CPDF_Name>("Subtype", "Form");
+ stream_dict->SetMatrixFor("Matrix", CFX_Matrix());
- RetainPtr<CPDF_Dictionary> pAPDict =
- pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP);
- pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
+ CFX_FloatRect rect = is_text_markup_annotation
+ ? CPDF_Annot::BoundingRectFromQuadPoints(annot_dict)
+ : annot_dict->GetRectFor(pdfium::annotation::kRect);
+ stream_dict->SetRectFor("BBox", rect);
+ stream_dict->SetFor("Resources", std::move(resource_dict));
- RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict();
- pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
- pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
- pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
- pStreamDict->SetMatrixFor("Matrix", CFX_Matrix());
+ auto normal_stream = doc->NewIndirect<CPDF_Stream>(std::move(stream_dict));
+ normal_stream->SetDataFromStringstream(app_stream);
- CFX_FloatRect rect = bIsTextMarkupAnnotation
- ? CPDF_Annot::BoundingRectFromQuadPoints(pAnnotDict)
- : pAnnotDict->GetRectFor(pdfium::annotation::kRect);
- pStreamDict->SetRectFor("BBox", rect);
- pStreamDict->SetFor("Resources", pResourceDict);
+ RetainPtr<CPDF_Dictionary> ap_dict =
+ annot_dict->GetOrCreateDictFor(pdfium::annotation::kAP);
+ ap_dict->SetNewFor<CPDF_Reference>("N", doc, normal_stream->GetObjNum());
}
bool GenerateCircleAP(CPDF_Document* pDoc, CPDF_Dictionary* pAnnotDict) {
@@ -1060,12 +1060,9 @@
RetainPtr<CPDF_Dictionary> pAPDict =
pAnnotDict->GetOrCreateDictFor(pdfium::annotation::kAP);
RetainPtr<CPDF_Stream> pNormalStream = pAPDict->GetMutableStreamFor("N");
- if (!pNormalStream) {
- pNormalStream = pDoc->NewIndirect<CPDF_Stream>();
- pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
- }
- RetainPtr<CPDF_Dictionary> pStreamDict = pNormalStream->GetMutableDict();
- if (pStreamDict) {
+ RetainPtr<CPDF_Dictionary> pStreamDict;
+ if (pNormalStream) {
+ pStreamDict = pNormalStream->GetMutableDict();
RetainPtr<CPDF_Dictionary> pStreamResList =
pStreamDict->GetMutableDictFor("Resources");
if (pStreamResList) {
@@ -1086,6 +1083,10 @@
}
pStreamDict->SetMatrixFor("Matrix", matrix);
pStreamDict->SetRectFor("BBox", rcBBox);
+ } else {
+ pNormalStream =
+ pDoc->NewIndirect<CPDF_Stream>(pdfium::MakeRetain<CPDF_Dictionary>());
+ pAPDict->SetNewFor<CPDF_Reference>("N", pDoc, pNormalStream->GetObjNum());
}
CPVT_FontMap map(
pDoc, pStreamDict ? pStreamDict->GetMutableDictFor("Resources") : nullptr,
diff --git a/fpdfsdk/fpdf_annot.cpp b/fpdfsdk/fpdf_annot.cpp
index 0cba33e..4005f05 100644
--- a/fpdfsdk/fpdf_annot.cpp
+++ b/fpdfsdk/fpdf_annot.cpp
@@ -1062,63 +1062,64 @@
static_assert(std::size(kModeKeyForMode) == FPDF_ANNOT_APPEARANCEMODE_COUNT,
"length of kModeKeyForMode should be equal to "
"FPDF_ANNOT_APPEARANCEMODE_COUNT");
- const char* modeKey = kModeKeyForMode[appearanceMode];
+ const char* mode_key = kModeKeyForMode[appearanceMode];
RetainPtr<CPDF_Dictionary> pApDict =
pAnnotDict->GetMutableDictFor(pdfium::annotation::kAP);
- // If value is null, we're in remove mode. Otherwise, we're in add/update
- // mode.
- if (value) {
- // Annotation object's non-empty bounding rect will be used as the /BBox
- // for the associated /XObject object
- CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect);
- constexpr float kMinSize = 0.000001f;
- if (rect.Width() < kMinSize || rect.Height() < kMinSize)
- return false;
-
- CPDF_AnnotContext* pAnnotContext =
- CPDFAnnotContextFromFPDFAnnotation(annot);
-
- CPDF_Document* pDoc = pAnnotContext->GetPage()->GetDocument();
- if (!pDoc)
- return false;
-
- auto pNewIndirectStream = pDoc->NewIndirect<CPDF_Stream>();
- ByteString newAPStream =
- PDF_EncodeText(WideStringFromFPDFWideString(value).AsStringView());
- pNewIndirectStream->SetData(newAPStream.raw_span());
-
- RetainPtr<CPDF_Dictionary> pStreamDict =
- pNewIndirectStream->GetMutableDict();
- pStreamDict->SetNewFor<CPDF_Name>(pdfium::annotation::kType, "XObject");
- pStreamDict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Form");
- pStreamDict->SetRectFor("BBox", rect);
- // Transparency values are specified in range [0.0f, 1.0f]. We are strictly
- // checking for value < 1 and not <= 1 so that the output PDF size does not
- // unnecessarily bloat up by creating a new dictionary in case of solid
- // color.
- if (pAnnotDict->KeyExist("CA") && pAnnotDict->GetFloatFor("CA") < 1.0f) {
- RetainPtr<CPDF_Dictionary> pResourceDict =
- SetExtGStateInResourceDict(pDoc, pAnnotDict.Get(), "Normal");
- pStreamDict->SetFor("Resources", pResourceDict);
- }
-
- // Storing reference to indirect object in annotation's AP
- if (!pApDict) {
- pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>(pdfium::annotation::kAP);
- }
- pApDict->SetNewFor<CPDF_Reference>(modeKey, pDoc,
- pNewIndirectStream->GetObjNum());
- } else {
+ // If `value` is null, then the action is to remove.
+ if (!value) {
if (pApDict) {
- if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL)
+ if (appearanceMode == FPDF_ANNOT_APPEARANCEMODE_NORMAL) {
pAnnotDict->RemoveFor(pdfium::annotation::kAP);
- else
- pApDict->RemoveFor(modeKey);
+ } else {
+ pApDict->RemoveFor(mode_key);
+ }
}
+ return true;
}
+ // Otherwise, add/update when `value` is non-null.
+ //
+ // Annotation object's non-empty bounding rect will be used as the /BBox
+ // for the associated /XObject object
+ CFX_FloatRect rect = pAnnotDict->GetRectFor(pdfium::annotation::kRect);
+ constexpr float kMinSize = 0.000001f;
+ if (rect.Width() < kMinSize || rect.Height() < kMinSize) {
+ return false;
+ }
+
+ CPDF_AnnotContext* pAnnotContext = CPDFAnnotContextFromFPDFAnnotation(annot);
+
+ CPDF_Document* pDoc = pAnnotContext->GetPage()->GetDocument();
+ if (!pDoc) {
+ return false;
+ }
+
+ auto stream_dict = pdfium::MakeRetain<CPDF_Dictionary>();
+ stream_dict->SetNewFor<CPDF_Name>(pdfium::annotation::kType, "XObject");
+ stream_dict->SetNewFor<CPDF_Name>(pdfium::annotation::kSubtype, "Form");
+ stream_dict->SetRectFor("BBox", rect);
+ // Transparency values are specified in range [0.0f, 1.0f]. We are strictly
+ // checking for value < 1 and not <= 1 so that the output PDF size does not
+ // unnecessarily bloat up by creating a new dictionary in case of solid
+ // color.
+ if (pAnnotDict->KeyExist("CA") && pAnnotDict->GetFloatFor("CA") < 1.0f) {
+ stream_dict->SetFor("Resources", SetExtGStateInResourceDict(
+ pDoc, pAnnotDict.Get(), "Normal"));
+ }
+
+ auto new_stream = pDoc->NewIndirect<CPDF_Stream>(std::move(stream_dict));
+ ByteString new_stream_data =
+ PDF_EncodeText(WideStringFromFPDFWideString(value).AsStringView());
+ new_stream->SetData(new_stream_data.raw_span());
+
+ // Storing reference to indirect object in annotation's AP
+ if (!pApDict) {
+ pApDict = pAnnotDict->SetNewFor<CPDF_Dictionary>(pdfium::annotation::kAP);
+ }
+ pApDict->SetNewFor<CPDF_Reference>(mode_key, pDoc, new_stream->GetObjNum());
+
return true;
}