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;
 }