Remove AppendObject from CPDF_Creator

The AppendObject method has been removed and the functionality moved
to the individual CPDF_Object classes.

Change-Id: I5446c6cc3e792d849acf77caed34b63a88f3a2d2
Reviewed-on: https://pdfium-review.googlesource.com/5072
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/fpdf_edit_create.cpp b/core/fpdfapi/edit/fpdf_edit_create.cpp
index 63c0930..5b4c3ad 100644
--- a/core/fpdfapi/edit/fpdf_edit_create.cpp
+++ b/core/fpdfapi/edit/fpdf_edit_create.cpp
@@ -34,155 +34,6 @@
 const uint32_t kXRefStreamMaxSize = 10000;
 const int kObjectStreamMaxLength = 256 * 1024;
 
-int32_t AppendObject(const CPDF_Object* pObj,
-                     CFX_FileBufferArchive* pFile,
-                     FX_FILESIZE& offset) {
-  int32_t len = 0;
-  if (!pObj) {
-    if (pFile->AppendString(" null") < 0)
-      return -1;
-
-    offset += 5;
-    return 1;
-  }
-  switch (pObj->GetType()) {
-    case CPDF_Object::NULLOBJ:
-      if (pFile->AppendString(" null") < 0)
-        return -1;
-
-      offset += 5;
-      break;
-    case CPDF_Object::BOOLEAN:
-    case CPDF_Object::NUMBER:
-      if (pFile->AppendString(" ") < 0)
-        return -1;
-      if ((len = pFile->AppendString(pObj->GetString().AsStringC())) < 0)
-        return -1;
-
-      offset += len + 1;
-      break;
-    case CPDF_Object::STRING: {
-      CFX_ByteString str = pObj->GetString();
-      bool bHex = pObj->AsString()->IsHex();
-      if ((len = pFile->AppendString(PDF_EncodeString(str, bHex).AsStringC())) <
-          0) {
-        return -1;
-      }
-      offset += len;
-      break;
-    }
-    case CPDF_Object::NAME: {
-      if (pFile->AppendString("/") < 0)
-        return -1;
-
-      CFX_ByteString str = pObj->GetString();
-      if ((len = pFile->AppendString(PDF_NameEncode(str).AsStringC())) < 0)
-        return -1;
-
-      offset += len + 1;
-      break;
-    }
-    case CPDF_Object::REFERENCE: {
-      if (pFile->AppendString(" ") < 0)
-        return -1;
-      if ((len = pFile->AppendDWord(pObj->AsReference()->GetRefObjNum())) < 0)
-        return -1;
-      if (pFile->AppendString(" 0 R ") < 0)
-        return -1;
-
-      offset += len + 6;
-      break;
-    }
-    case CPDF_Object::ARRAY: {
-      if (pFile->AppendString("[") < 0)
-        return -1;
-
-      offset += 1;
-      const CPDF_Array* p = pObj->AsArray();
-      for (size_t i = 0; i < p->GetCount(); i++) {
-        CPDF_Object* pElement = p->GetObjectAt(i);
-        if (!pElement->IsInline()) {
-          if (pFile->AppendString(" ") < 0)
-            return -1;
-          if ((len = pFile->AppendDWord(pElement->GetObjNum())) < 0)
-            return -1;
-          if (pFile->AppendString(" 0 R") < 0)
-            return -1;
-
-          offset += len + 5;
-        } else {
-          if (AppendObject(pElement, pFile, offset) < 0)
-            return -1;
-        }
-      }
-      if (pFile->AppendString("]") < 0)
-        return -1;
-
-      offset += 1;
-      break;
-    }
-    case CPDF_Object::DICTIONARY: {
-      if (pFile->AppendString("<<") < 0)
-        return -1;
-
-      offset += 2;
-      const CPDF_Dictionary* p = pObj->AsDictionary();
-      for (const auto& it : *p) {
-        const CFX_ByteString& key = it.first;
-        CPDF_Object* pValue = it.second.get();
-        if (pFile->AppendString("/") < 0)
-          return -1;
-        if ((len = pFile->AppendString(PDF_NameEncode(key).AsStringC())) < 0)
-          return -1;
-
-        offset += len + 1;
-        if (!pValue->IsInline()) {
-          if (pFile->AppendString(" ") < 0)
-            return -1;
-          if ((len = pFile->AppendDWord(pValue->GetObjNum())) < 0)
-            return -1;
-          if (pFile->AppendString(" 0 R") < 0)
-            return -1;
-
-          offset += len + 5;
-        } else {
-          if (AppendObject(pValue, pFile, offset) < 0)
-            return -1;
-        }
-      }
-      if (pFile->AppendString(">>") < 0)
-        return -1;
-
-      offset += 2;
-      break;
-    }
-    case CPDF_Object::STREAM: {
-      const CPDF_Stream* p = pObj->AsStream();
-      if (AppendObject(p->GetDict(), pFile, offset) < 0)
-        return -1;
-      if (pFile->AppendString("stream\r\n") < 0)
-        return -1;
-
-      offset += 8;
-      auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(p);
-      pAcc->LoadAllData(true);
-      if (pFile->AppendBlock(pAcc->GetData(), pAcc->GetSize()) < 0)
-        return -1;
-
-      offset += pAcc->GetSize();
-      if ((len = pFile->AppendString("\r\nendstream")) < 0)
-        return -1;
-
-      offset += len;
-      break;
-    }
-    default:
-      ASSERT(false);
-      break;
-  }
-  return 1;
-}
-
 int32_t WriteTrailer(CPDF_Document* pDocument,
                      CFX_FileBufferArchive* pFile,
                      CPDF_Array* pIDArray) {
@@ -217,7 +68,7 @@
 
         offset += len + 6;
       } else {
-        if (AppendObject(pValue, pFile, offset) < 0)
+        if (!pValue->WriteTo(pFile, &offset))
           return -1;
       }
     }
@@ -226,7 +77,7 @@
         return -1;
 
       offset += 3;
-      if (AppendObject(pIDArray, pFile, offset) < 0)
+      if (!pIDArray->WriteTo(pFile, &offset))
         return -1;
     }
     return offset;
@@ -254,7 +105,7 @@
       return -1;
 
     offset += 3;
-    if (AppendObject(pIDArray, pFile, offset) < 0)
+    if (!pIDArray->WriteTo(pFile, &offset))
       return -1;
   }
   return offset;
@@ -992,40 +843,22 @@
 int32_t CPDF_Creator::WriteDirectObj(uint32_t objnum,
                                      const CPDF_Object* pObj,
                                      bool bEncrypt) {
-  int32_t len = 0;
-  if (!pObj) {
-    if (m_File.AppendString(" null") < 0)
-      return -1;
-
-    m_Offset += 5;
-    return 1;
-  }
-
   switch (pObj->GetType()) {
-    case CPDF_Object::NULLOBJ:
-      if (m_File.AppendString(" null") < 0)
-        return -1;
-
-      m_Offset += 5;
-      break;
     case CPDF_Object::BOOLEAN:
+    case CPDF_Object::NAME:
+    case CPDF_Object::NULLOBJ:
     case CPDF_Object::NUMBER:
-      if (m_File.AppendString(" ") < 0)
+    case CPDF_Object::REFERENCE:
+      if (!pObj->WriteTo(&m_File, &m_Offset))
         return -1;
-      if ((len = m_File.AppendString(pObj->GetString().AsStringC())) < 0)
-        return -1;
-
-      m_Offset += len + 1;
       break;
+
     case CPDF_Object::STRING: {
       CFX_ByteString str = pObj->GetString();
       bool bHex = pObj->AsString()->IsHex();
       if (!m_pCryptoHandler || !bEncrypt) {
-        CFX_ByteString content = PDF_EncodeString(str, bHex);
-        if ((len = m_File.AppendString(content.AsStringC())) < 0)
+        if (!pObj->WriteTo(&m_File, &m_Offset))
           return -1;
-
-        m_Offset += len;
         break;
       }
       CPDF_Encryptor encryptor(m_pCryptoHandler.Get(), objnum,
@@ -1033,7 +866,8 @@
       CFX_ByteString content = PDF_EncodeString(
           CFX_ByteString((const char*)encryptor.m_pData, encryptor.m_dwSize),
           bHex);
-      if ((len = m_File.AppendString(content.AsStringC())) < 0)
+      int32_t len = m_File.AppendString(content.AsStringC());
+      if (len < 0)
         return -1;
 
       m_Offset += len;
@@ -1052,7 +886,9 @@
       }
       if (WriteDirectObj(objnum, encoder.m_pDict.Get()) < 0)
         return -1;
-      if ((len = m_File.AppendString("stream\r\n")) < 0)
+
+      int32_t len = m_File.AppendString("stream\r\n");
+      if (len < 0)
         return -1;
 
       m_Offset += len;
@@ -1060,33 +896,13 @@
         return -1;
 
       m_Offset += encryptor.m_dwSize;
-      if ((len = m_File.AppendString("\r\nendstream")) < 0)
+      len = m_File.AppendString("\r\nendstream");
+      if (len < 0)
         return -1;
 
       m_Offset += len;
       break;
     }
-    case CPDF_Object::NAME: {
-      if (m_File.AppendString("/") < 0)
-        return -1;
-
-      CFX_ByteString str = pObj->GetString();
-      if ((len = m_File.AppendString(PDF_NameEncode(str).AsStringC())) < 0)
-        return -1;
-
-      m_Offset += len + 1;
-      break;
-    }
-    case CPDF_Object::REFERENCE: {
-      if (m_File.AppendString(" ") < 0)
-        return -1;
-      if ((len = m_File.AppendDWord(pObj->AsReference()->GetRefObjNum())) < 0)
-        return -1;
-      if (m_File.AppendString(" 0 R") < 0)
-        return -1;
-      m_Offset += len + 5;
-      break;
-    }
     case CPDF_Object::ARRAY: {
       if (m_File.AppendString("[") < 0)
         return -1;
@@ -1098,7 +914,9 @@
         if (!pElement->IsInline()) {
           if (m_File.AppendString(" ") < 0)
             return -1;
-          if ((len = m_File.AppendDWord(pElement->GetObjNum())) < 0)
+
+          int32_t len = m_File.AppendDWord(pElement->GetObjNum());
+          if (len < 0)
             return -1;
           if (m_File.AppendString(" 0 R") < 0)
             return -1;
@@ -1116,8 +934,12 @@
       break;
     }
     case CPDF_Object::DICTIONARY: {
-      if (!m_pCryptoHandler || pObj == m_pEncryptDict)
-        return AppendObject(pObj, &m_File, m_Offset);
+      if (!m_pCryptoHandler || pObj == m_pEncryptDict) {
+        if (!pObj->WriteTo(&m_File, &m_Offset))
+          return -1;
+        break;
+      }
+
       if (m_File.AppendString("<<") < 0)
         return -1;
 
@@ -1130,7 +952,9 @@
         CPDF_Object* pValue = it.second.get();
         if (m_File.AppendString("/") < 0)
           return -1;
-        if ((len = m_File.AppendString(PDF_NameEncode(key).AsStringC())) < 0)
+
+        int32_t len = m_File.AppendString(PDF_NameEncode(key).AsStringC());
+        if (len < 0)
           return -1;
 
         m_Offset += len + 1;
@@ -1140,7 +964,9 @@
         if (!pValue->IsInline()) {
           if (m_File.AppendString(" ") < 0)
             return -1;
-          if ((len = m_File.AppendDWord(pValue->GetObjNum())) < 0)
+
+          len = m_File.AppendDWord(pValue->GetObjNum());
+          if (len < 0)
             return -1;
           if (m_File.AppendString(" 0 R ") < 0)
             return -1;
@@ -1574,7 +1400,7 @@
             return -1;
         } else {
           FX_FILESIZE offset = 0;
-          if (AppendObject(pValue, &m_File, offset) < 0)
+          if (!pValue->WriteTo(&m_File, &offset))
             return -1;
         }
       }
@@ -1631,7 +1457,7 @@
         return -1;
 
       FX_FILESIZE offset = 0;
-      if (AppendObject(m_pIDArray.get(), &m_File, offset) < 0)
+      if (!m_pIDArray->WriteTo(&m_File, &offset))
         return -1;
     }
     if (!bXRefStream) {
diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp
index f3c23f3..aa10588 100644
--- a/core/fpdfapi/parser/cpdf_array.cpp
+++ b/core/fpdfapi/parser/cpdf_array.cpp
@@ -193,3 +193,32 @@
   m_Objects.push_back(std::move(pObj));
   return pRet;
 }
+
+bool CPDF_Array::WriteTo(CFX_FileBufferArchive* archive,
+                         FX_FILESIZE* offset) const {
+  if (archive->AppendString("[") < 0)
+    return false;
+  *offset += 1;
+
+  for (size_t i = 0; i < GetCount(); ++i) {
+    CPDF_Object* pElement = GetObjectAt(i);
+    if (!pElement->IsInline()) {
+      if (archive->AppendString(" ") < 0)
+        return false;
+
+      int32_t len = archive->AppendDWord(pElement->GetObjNum());
+      if (len < 0)
+        return false;
+      if (archive->AppendString(" 0 R") < 0)
+        return false;
+      *offset += len + 5;
+    } else {
+      if (!pElement->WriteTo(archive, offset))
+        return false;
+    }
+  }
+  if (archive->AppendString("]") < 0)
+    return false;
+  *offset += 1;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h
index 8f8b600..b788d1c 100644
--- a/core/fpdfapi/parser/cpdf_array.h
+++ b/core/fpdfapi/parser/cpdf_array.h
@@ -34,6 +34,8 @@
   bool IsArray() const override;
   CPDF_Array* AsArray() override;
   const CPDF_Array* AsArray() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   bool IsEmpty() const { return m_Objects.empty(); }
   size_t GetCount() const { return m_Objects.size(); }
diff --git a/core/fpdfapi/parser/cpdf_boolean.cpp b/core/fpdfapi/parser/cpdf_boolean.cpp
index 0204fd9..1cee3a3 100644
--- a/core/fpdfapi/parser/cpdf_boolean.cpp
+++ b/core/fpdfapi/parser/cpdf_boolean.cpp
@@ -44,3 +44,15 @@
 const CPDF_Boolean* CPDF_Boolean::AsBoolean() const {
   return this;
 }
+
+bool CPDF_Boolean::WriteTo(CFX_FileBufferArchive* archive,
+                           FX_FILESIZE* offset) const {
+  if (archive->AppendString(" ") < 0)
+    return false;
+
+  int32_t len = archive->AppendString(GetString().AsStringC());
+  if (len < 0)
+    return false;
+  *offset += len + 1;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_boolean.h b/core/fpdfapi/parser/cpdf_boolean.h
index afebc29..e859f4c 100644
--- a/core/fpdfapi/parser/cpdf_boolean.h
+++ b/core/fpdfapi/parser/cpdf_boolean.h
@@ -28,6 +28,8 @@
   bool IsBoolean() const override;
   CPDF_Boolean* AsBoolean() override;
   const CPDF_Boolean* AsBoolean() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
  protected:
   bool m_bValue;
diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp
index d4e4080..7d84083 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.cpp
+++ b/core/fpdfapi/parser/cpdf_dictionary.cpp
@@ -16,6 +16,7 @@
 #include "core/fpdfapi/parser/cpdf_reference.h"
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fpdfapi/parser/fpdf_parser_decode.h"
 #include "third_party/base/logging.h"
 #include "third_party/base/stl_util.h"
 
@@ -237,3 +238,41 @@
 CFX_ByteString CPDF_Dictionary::MaybeIntern(const CFX_ByteString& str) {
   return m_pPool ? m_pPool->Intern(str) : str;
 }
+
+bool CPDF_Dictionary::WriteTo(CFX_FileBufferArchive* archive,
+                              FX_FILESIZE* offset) const {
+  if (archive->AppendString("<<") < 0)
+    return false;
+  *offset += 2;
+
+  for (const auto& it : *this) {
+    const CFX_ByteString& key = it.first;
+    CPDF_Object* pValue = it.second.get();
+    if (archive->AppendString("/") < 0)
+      return false;
+
+    int32_t len = archive->AppendString(PDF_NameEncode(key).AsStringC());
+    if (len < 0)
+      return false;
+    *offset += len + 1;
+
+    if (!pValue->IsInline()) {
+      if (archive->AppendString(" ") < 0)
+        return false;
+
+      len = archive->AppendDWord(pValue->GetObjNum());
+      if (len < 0)
+        return false;
+      if (archive->AppendString(" 0 R") < 0)
+        return false;
+      *offset += len + 5;
+    } else {
+      if (!pValue->WriteTo(archive, offset))
+        return false;
+    }
+  }
+  if (archive->AppendString(">>") < 0)
+    return false;
+  *offset += 2;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h
index b14574f..e4144c1 100644
--- a/core/fpdfapi/parser/cpdf_dictionary.h
+++ b/core/fpdfapi/parser/cpdf_dictionary.h
@@ -37,6 +37,8 @@
   bool IsDictionary() const override;
   CPDF_Dictionary* AsDictionary() override;
   const CPDF_Dictionary* AsDictionary() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   size_t GetCount() const { return m_Map.size(); }
   CPDF_Object* GetObjectFor(const CFX_ByteString& key) const;
diff --git a/core/fpdfapi/parser/cpdf_name.cpp b/core/fpdfapi/parser/cpdf_name.cpp
index 5be64d3..74c83b9 100644
--- a/core/fpdfapi/parser/cpdf_name.cpp
+++ b/core/fpdfapi/parser/cpdf_name.cpp
@@ -49,3 +49,16 @@
 CFX_WideString CPDF_Name::GetUnicodeText() const {
   return PDF_DecodeText(m_Name);
 }
+
+bool CPDF_Name::WriteTo(CFX_FileBufferArchive* archive,
+                        FX_FILESIZE* offset) const {
+  if (archive->AppendString("/") < 0)
+    return false;
+
+  CFX_ByteString str = GetString();
+  int32_t len = archive->AppendString(PDF_NameEncode(str).AsStringC());
+  if (len < 0)
+    return false;
+  *offset += len + 1;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_name.h b/core/fpdfapi/parser/cpdf_name.h
index 61318d4..8855f97 100644
--- a/core/fpdfapi/parser/cpdf_name.h
+++ b/core/fpdfapi/parser/cpdf_name.h
@@ -27,6 +27,8 @@
   bool IsName() const override;
   CPDF_Name* AsName() override;
   const CPDF_Name* AsName() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
  protected:
   CFX_ByteString m_Name;
diff --git a/core/fpdfapi/parser/cpdf_null.cpp b/core/fpdfapi/parser/cpdf_null.cpp
index 41478d7..b5e07e0 100644
--- a/core/fpdfapi/parser/cpdf_null.cpp
+++ b/core/fpdfapi/parser/cpdf_null.cpp
@@ -16,3 +16,11 @@
 std::unique_ptr<CPDF_Object> CPDF_Null::Clone() const {
   return pdfium::MakeUnique<CPDF_Null>();
 }
+
+bool CPDF_Null::WriteTo(CFX_FileBufferArchive* archive,
+                        FX_FILESIZE* offset) const {
+  if (archive->AppendString(" null") < 0)
+    return false;
+  *offset += 5;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_null.h b/core/fpdfapi/parser/cpdf_null.h
index 4f8420f..b6b781b 100644
--- a/core/fpdfapi/parser/cpdf_null.h
+++ b/core/fpdfapi/parser/cpdf_null.h
@@ -18,6 +18,8 @@
   // CPDF_Object.
   Type GetType() const override;
   std::unique_ptr<CPDF_Object> Clone() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 };
 
 #endif  // CORE_FPDFAPI_PARSER_CPDF_NULL_H_
diff --git a/core/fpdfapi/parser/cpdf_number.cpp b/core/fpdfapi/parser/cpdf_number.cpp
index c83b9dc..24665ff 100644
--- a/core/fpdfapi/parser/cpdf_number.cpp
+++ b/core/fpdfapi/parser/cpdf_number.cpp
@@ -55,3 +55,15 @@
   return m_bInteger ? CFX_ByteString::FormatInteger(m_Integer, FXFORMAT_SIGNED)
                     : CFX_ByteString::FormatFloat(m_Float);
 }
+
+bool CPDF_Number::WriteTo(CFX_FileBufferArchive* archive,
+                          FX_FILESIZE* offset) const {
+  if (archive->AppendString(" ") < 0)
+    return false;
+
+  int32_t len = archive->AppendString(GetString().AsStringC());
+  if (len < 0)
+    return false;
+  *offset += len + 1;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_number.h b/core/fpdfapi/parser/cpdf_number.h
index 6e85044..a5d866f 100644
--- a/core/fpdfapi/parser/cpdf_number.h
+++ b/core/fpdfapi/parser/cpdf_number.h
@@ -31,6 +31,8 @@
   bool IsNumber() const override;
   CPDF_Number* AsNumber() override;
   const CPDF_Number* AsNumber() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   bool IsInteger() const { return m_bInteger; }
 
diff --git a/core/fpdfapi/parser/cpdf_object.h b/core/fpdfapi/parser/cpdf_object.h
index 6165737..8194256 100644
--- a/core/fpdfapi/parser/cpdf_object.h
+++ b/core/fpdfapi/parser/cpdf_object.h
@@ -11,6 +11,7 @@
 #include <set>
 #include <type_traits>
 
+#include "core/fxcrt/fx_basic.h"
 #include "core/fxcrt/fx_string.h"
 #include "core/fxcrt/fx_system.h"
 
@@ -88,6 +89,9 @@
   virtual CPDF_String* AsString();
   virtual const CPDF_String* AsString() const;
 
+  virtual bool WriteTo(CFX_FileBufferArchive* archive,
+                       FX_FILESIZE* offset) const = 0;
+
  protected:
   friend class CPDF_Array;
   friend class CPDF_Dictionary;
diff --git a/core/fpdfapi/parser/cpdf_reference.cpp b/core/fpdfapi/parser/cpdf_reference.cpp
index 942bae5..560fd27 100644
--- a/core/fpdfapi/parser/cpdf_reference.cpp
+++ b/core/fpdfapi/parser/cpdf_reference.cpp
@@ -82,3 +82,16 @@
   return m_pObjList ? m_pObjList->GetOrParseIndirectObject(m_RefObjNum)
                     : nullptr;
 }
+
+bool CPDF_Reference::WriteTo(CFX_FileBufferArchive* archive,
+                             FX_FILESIZE* offset) const {
+  if (archive->AppendString(" ") < 0)
+    return false;
+  int32_t len = archive->AppendDWord(GetRefObjNum());
+  if (len < 0)
+    return false;
+  if (archive->AppendString(" 0 R ") < 0)
+    return false;
+  *offset += len + 6;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h
index ff88755..4830cb5 100644
--- a/core/fpdfapi/parser/cpdf_reference.h
+++ b/core/fpdfapi/parser/cpdf_reference.h
@@ -30,6 +30,8 @@
   bool IsReference() const override;
   CPDF_Reference* AsReference() override;
   const CPDF_Reference* AsReference() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   CPDF_IndirectObjectHolder* GetObjList() const { return m_pObjList; }
   uint32_t GetRefObjNum() const { return m_RefObjNum; }
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index e4f279a..7e2529e 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -131,3 +131,25 @@
   pAcc->LoadAllData(false);
   return PDF_DecodeText(pAcc->GetData(), pAcc->GetSize());
 }
+
+bool CPDF_Stream::WriteTo(CFX_FileBufferArchive* archive,
+                          FX_FILESIZE* offset) const {
+  if (!GetDict()->WriteTo(archive, offset))
+    return false;
+  if (archive->AppendString("stream\r\n") < 0)
+    return false;
+  *offset += 8;
+
+  auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this);
+  pAcc->LoadAllData(true);
+  if (archive->AppendBlock(pAcc->GetData(), pAcc->GetSize()) < 0)
+    return false;
+  *offset += pAcc->GetSize();
+
+  int32_t len = archive->AppendString("\r\nendstream");
+  if (len < 0)
+    return false;
+
+  *offset += len;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h
index 902cd75..4f76953 100644
--- a/core/fpdfapi/parser/cpdf_stream.h
+++ b/core/fpdfapi/parser/cpdf_stream.h
@@ -33,6 +33,8 @@
   bool IsStream() const override;
   CPDF_Stream* AsStream() override;
   const CPDF_Stream* AsStream() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   uint32_t GetRawSize() const { return m_dwSize; }
   uint8_t* GetRawData() const { return m_pDataBuf.get(); }
diff --git a/core/fpdfapi/parser/cpdf_string.cpp b/core/fpdfapi/parser/cpdf_string.cpp
index 06bae54..01cf3ff 100644
--- a/core/fpdfapi/parser/cpdf_string.cpp
+++ b/core/fpdfapi/parser/cpdf_string.cpp
@@ -64,3 +64,14 @@
 CFX_WideString CPDF_String::GetUnicodeText() const {
   return PDF_DecodeText(m_String);
 }
+
+bool CPDF_String::WriteTo(CFX_FileBufferArchive* archive,
+                          FX_FILESIZE* offset) const {
+  CFX_ByteString str = GetString();
+  int32_t len =
+      archive->AppendString(PDF_EncodeString(str, IsHex()).AsStringC());
+  if (len < 0)
+    return false;
+  *offset += len;
+  return true;
+}
diff --git a/core/fpdfapi/parser/cpdf_string.h b/core/fpdfapi/parser/cpdf_string.h
index 6698d8c..f895535 100644
--- a/core/fpdfapi/parser/cpdf_string.h
+++ b/core/fpdfapi/parser/cpdf_string.h
@@ -33,6 +33,8 @@
   bool IsString() const override;
   CPDF_String* AsString() override;
   const CPDF_String* AsString() const override;
+  bool WriteTo(CFX_FileBufferArchive* archive,
+               FX_FILESIZE* offset) const override;
 
   bool IsHex() const { return m_bHex; }