Add CPDF_Stream::ReplaceData method.

Change-Id: I94b2e8f6fd522b97c917037e32fb3bcbeea0cbeb
Reviewed-on: https://pdfium-review.googlesource.com/8911
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index 7d474b2..ffaa264 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -785,6 +785,51 @@
   EXPECT_EQ(42, array->GetIntegerAt(0));
 }
 
+TEST(PDFStreamTest, SetData) {
+  std::vector<uint8_t> data(100);
+  auto stream = pdfium::MakeUnique<CPDF_Stream>();
+  stream->InitStream(data.data(), data.size(),
+                     pdfium::MakeUnique<CPDF_Dictionary>());
+  EXPECT_EQ(static_cast<int>(data.size()),
+            stream->GetDict()->GetIntegerFor("Length"));
+
+  stream->GetDict()->SetNewFor<CPDF_String>("Filter", L"SomeFilter");
+  stream->GetDict()->SetNewFor<CPDF_String>("DecodeParms", L"SomeParams");
+
+  std::vector<uint8_t> new_data(data.size() * 2);
+  stream->SetData(new_data.data(), new_data.size());
+
+  // The "Length" field should be updated for new data size.
+  EXPECT_EQ(static_cast<int>(new_data.size()),
+            stream->GetDict()->GetIntegerFor("Length"));
+
+  // The "Filter" and "DecodeParms" fields should not be changed.
+  EXPECT_EQ(stream->GetDict()->GetUnicodeTextFor("Filter"), L"SomeFilter");
+  EXPECT_EQ(stream->GetDict()->GetUnicodeTextFor("DecodeParms"), L"SomeParams");
+}
+
+TEST(PDFStreamTest, SetDataAndRemoveFilter) {
+  std::vector<uint8_t> data(100);
+  auto stream = pdfium::MakeUnique<CPDF_Stream>();
+  stream->InitStream(data.data(), data.size(),
+                     pdfium::MakeUnique<CPDF_Dictionary>());
+  EXPECT_EQ(static_cast<int>(data.size()),
+            stream->GetDict()->GetIntegerFor("Length"));
+
+  stream->GetDict()->SetNewFor<CPDF_String>("Filter", L"SomeFilter");
+  stream->GetDict()->SetNewFor<CPDF_String>("DecodeParms", L"SomeParams");
+
+  std::vector<uint8_t> new_data(data.size() * 2);
+  stream->SetDataAndRemoveFilter(new_data.data(), new_data.size());
+  // The "Length" field should be updated for new data size.
+  EXPECT_EQ(static_cast<int>(new_data.size()),
+            stream->GetDict()->GetIntegerFor("Length"));
+
+  // The "Filter" and "DecodeParms" should be removed.
+  EXPECT_FALSE(stream->GetDict()->KeyExist("Filter"));
+  EXPECT_FALSE(stream->GetDict()->KeyExist("DecodeParms"));
+}
+
 TEST(PDFDictionaryTest, CloneDirectObject) {
   CPDF_IndirectObjectHolder objects_holder;
   auto dict = pdfium::MakeUnique<CPDF_Dictionary>();
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index ec12ac5..d430a4f 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -97,6 +97,17 @@
                                          std::move(pNewDict));
 }
 
+void CPDF_Stream::SetDataAndRemoveFilter(const uint8_t* pData, uint32_t size) {
+  SetData(pData, size);
+  m_pDict->RemoveFor("Filter");
+  m_pDict->RemoveFor("DecodeParms");
+}
+
+void CPDF_Stream::SetDataAndRemoveFilter(std::ostringstream* stream) {
+  SetDataAndRemoveFilter(
+      reinterpret_cast<const uint8_t*>(stream->str().c_str()), stream->tellp());
+}
+
 void CPDF_Stream::SetData(const uint8_t* pData, uint32_t size) {
   m_bMemoryBased = true;
   m_pDataBuf.reset(FX_Alloc(uint8_t, size));
@@ -106,8 +117,6 @@
   if (!m_pDict)
     m_pDict = pdfium::MakeUnique<CPDF_Dictionary>();
   m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(size));
-  m_pDict->RemoveFor("Filter");
-  m_pDict->RemoveFor("DecodeParms");
 }
 
 void CPDF_Stream::SetData(std::ostringstream* stream) {
diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h
index d58f608..2795f7d 100644
--- a/core/fpdfapi/parser/cpdf_stream.h
+++ b/core/fpdfapi/parser/cpdf_stream.h
@@ -42,6 +42,10 @@
   // Does not takes ownership of |pData|, copies into internally-owned buffer.
   void SetData(const uint8_t* pData, uint32_t size);
   void SetData(std::ostringstream* stream);
+  // Set data and remove "Filter" and "DecodeParms" fields from stream
+  // dictionary.
+  void SetDataAndRemoveFilter(const uint8_t* pData, uint32_t size);
+  void SetDataAndRemoveFilter(std::ostringstream* stream);
 
   void InitStream(const uint8_t* pData,
                   uint32_t size,
diff --git a/core/fpdfdoc/cpvt_generateap.cpp b/core/fpdfdoc/cpvt_generateap.cpp
index 956f912..d1abde6 100644
--- a/core/fpdfdoc/cpvt_generateap.cpp
+++ b/core/fpdfdoc/cpvt_generateap.cpp
@@ -429,7 +429,7 @@
     } break;
   }
   if (pNormalStream) {
-    pNormalStream->SetData(&sAppStream);
+    pNormalStream->SetDataAndRemoveFilter(&sAppStream);
     pStreamDict = pNormalStream->GetDict();
     if (pStreamDict) {
       pStreamDict->SetMatrixFor("Matrix", matrix);
diff --git a/fpdfsdk/fpdf_flatten.cpp b/fpdfsdk/fpdf_flatten.cpp
index e530553..16528c2 100644
--- a/fpdfsdk/fpdf_flatten.cpp
+++ b/fpdfsdk/fpdf_flatten.cpp
@@ -203,7 +203,8 @@
     CFX_ByteString sBody =
         CFX_ByteString((const char*)pAcc->GetData(), pAcc->GetSize());
     sStream = sStream + sBody + "\nQ";
-    pContentsStream->SetData(sStream.raw_str(), sStream.GetLength());
+    pContentsStream->SetDataAndRemoveFilter(sStream.raw_str(),
+                                            sStream.GetLength());
     pContentsArray->AddNew<CPDF_Reference>(pDocument,
                                            pContentsStream->GetObjNum());
     pPage->SetNewFor<CPDF_Reference>("Contents", pDocument,
@@ -405,7 +406,7 @@
     sTemp.Format("q %f 0 0 %f %f %f cm /%s Do Q\n", m.a, m.d, m.e, m.f,
                  sFormName.c_str());
     sStream += sTemp;
-    pNewXObject->SetData(sStream.raw_str(), sStream.GetLength());
+    pNewXObject->SetDataAndRemoveFilter(sStream.raw_str(), sStream.GetLength());
   }
   pPageDict->RemoveFor("Annots");
   return FLATTEN_SUCCESS;
diff --git a/fpdfsdk/fpdfannot.cpp b/fpdfsdk/fpdfannot.cpp
index fcbed5c..64c95a3 100644
--- a/fpdfsdk/fpdfannot.cpp
+++ b/fpdfsdk/fpdfannot.cpp
@@ -179,7 +179,7 @@
   CPDF_PageContentGenerator generator(pForm);
   std::ostringstream buf;
   generator.ProcessPageObjects(&buf);
-  pStream->SetData(&buf);
+  pStream->SetDataAndRemoveFilter(&buf);
 }
 
 }  // namespace
diff --git a/fpdfsdk/pwl/cpwl_appstream.cpp b/fpdfsdk/pwl/cpwl_appstream.cpp
index fe40163..405a205 100644
--- a/fpdfsdk/pwl/cpwl_appstream.cpp
+++ b/fpdfsdk/pwl/cpwl_appstream.cpp
@@ -1943,7 +1943,8 @@
   }
   pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
   pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
-  pStream->SetData((uint8_t*)(sContents.c_str()), sContents.GetLength());
+  pStream->SetDataAndRemoveFilter((uint8_t*)(sContents.c_str()),
+                                  sContents.GetLength());
 }
 
 void CPWL_AppStream::Remove(const CFX_ByteString& sAPType) {