diff options
author | Artem Strygin <art-snake@yandex-team.ru> | 2018-07-23 19:54:34 +0000 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2018-07-23 19:54:34 +0000 |
commit | 2bfa78540c375916ec9973f0ae11271b098180bd (patch) | |
tree | 4ec0b11e0014c95acda8a2e0b54e1bacd9f349d1 | |
parent | 9f53dc093a9d00342ea76ecc0b4c8c84357ffd6e (diff) | |
download | pdfium-2bfa78540c375916ec9973f0ae11271b098180bd.tar.xz |
Rework of CPDF_Object writing.
Move writing logic into implementation of related clases.
Change-Id: If70dc418b352b562ee681ea34fa6595d6f52eee3
Reviewed-on: https://pdfium-review.googlesource.com/36350
Commit-Queue: Art Snake <art-snake@yandex-team.ru>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
24 files changed, 125 insertions, 184 deletions
diff --git a/core/fpdfapi/edit/cpdf_creator.cpp b/core/fpdfapi/edit/cpdf_creator.cpp index f5d8c0fe49..5d4fac478d 100644 --- a/core/fpdfapi/edit/cpdf_creator.cpp +++ b/core/fpdfapi/edit/cpdf_creator.cpp @@ -151,143 +151,20 @@ CPDF_Creator::CPDF_Creator(CPDF_Document* pDoc, CPDF_Creator::~CPDF_Creator() {} -bool CPDF_Creator::WriteStream(const CPDF_Object* pStream, uint32_t objnum) { - CPDF_CryptoHandler* pCrypto = - pStream != m_pMetadata ? GetCryptoHandler() : nullptr; - - CPDF_FlateEncoder encoder(pStream->AsStream(), pStream != m_pMetadata); - CPDF_Encryptor encryptor(pCrypto, objnum, encoder.GetSpan()); - if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) != - encryptor.GetSpan().size()) { - encoder.CloneDict(); - encoder.GetClonedDict()->SetNewFor<CPDF_Number>( - "Length", static_cast<int>(encryptor.GetSpan().size())); - } - - if (!WriteDirectObj(objnum, encoder.GetDict(), true) || - !m_Archive->WriteString("stream\r\n")) { - return false; - } - - // Allow for empty streams. - if (encryptor.GetSpan().size() > 0 && - !m_Archive->WriteBlock(encryptor.GetSpan().data(), - encryptor.GetSpan().size())) { - return false; - } - - return m_Archive->WriteString("\r\nendstream"); -} - bool CPDF_Creator::WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj) { if (!m_Archive->WriteDWord(objnum) || !m_Archive->WriteString(" 0 obj\r\n")) return false; - if (pObj->IsStream()) { - if (!WriteStream(pObj, objnum)) - return false; - } else if (!WriteDirectObj(objnum, pObj, true)) { + std::unique_ptr<CPDF_Encryptor> encryptor; + if (GetCryptoHandler() && pObj != m_pEncryptDict) + encryptor = pdfium::MakeUnique<CPDF_Encryptor>(GetCryptoHandler(), objnum); + + if (!pObj->WriteTo(m_Archive.get(), encryptor.get())) return false; - } return m_Archive->WriteString("\r\nendobj\r\n"); } -bool CPDF_Creator::WriteDirectObj(uint32_t objnum, - const CPDF_Object* pObj, - bool bEncrypt) { - switch (pObj->GetType()) { - case CPDF_Object::BOOLEAN: - case CPDF_Object::NAME: - case CPDF_Object::NULLOBJ: - case CPDF_Object::NUMBER: - case CPDF_Object::REFERENCE: - if (!pObj->WriteTo(m_Archive.get())) - return false; - break; - - case CPDF_Object::STRING: { - ByteString str = pObj->GetString(); - bool bHex = pObj->AsString()->IsHex(); - if (!GetCryptoHandler() || !bEncrypt) { - if (!pObj->WriteTo(m_Archive.get())) - return false; - break; - } - CPDF_Encryptor encryptor(GetCryptoHandler(), objnum, str.AsRawSpan()); - ByteString content = PDF_EncodeString( - ByteString(encryptor.GetSpan().data(), encryptor.GetSpan().size()), - bHex); - if (!m_Archive->WriteString(content.AsStringView())) - return false; - break; - } - case CPDF_Object::STREAM: { - CPDF_FlateEncoder encoder(pObj->AsStream(), true); - CPDF_Encryptor encryptor(GetCryptoHandler(), objnum, encoder.GetSpan()); - if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) != - encryptor.GetSpan().size()) { - encoder.CloneDict(); - encoder.GetClonedDict()->SetNewFor<CPDF_Number>( - "Length", static_cast<int>(encryptor.GetSpan().size())); - } - if (!WriteDirectObj(objnum, encoder.GetDict(), true) || - !m_Archive->WriteString("stream\r\n") || - !m_Archive->WriteBlock(encryptor.GetSpan().data(), - encryptor.GetSpan().size()) || - !m_Archive->WriteString("\r\nendstream")) { - return false; - } - - break; - } - case CPDF_Object::ARRAY: { - if (!m_Archive->WriteString("[")) - return false; - - const CPDF_Array* p = pObj->AsArray(); - for (size_t i = 0; i < p->GetCount(); i++) { - if (!WriteDirectObj(objnum, p->GetObjectAt(i), true)) - return false; - } - if (!m_Archive->WriteString("]")) - return false; - break; - } - case CPDF_Object::DICTIONARY: { - if (!GetCryptoHandler() || pObj == m_pEncryptDict) { - if (!pObj->WriteTo(m_Archive.get())) - return false; - break; - } - - if (!m_Archive->WriteString("<<")) - return false; - - const CPDF_Dictionary* p = pObj->AsDictionary(); - bool bSignDict = p->IsSignatureDict(); - for (const auto& it : *p) { - bool bSignValue = false; - const ByteString& key = it.first; - CPDF_Object* pValue = it.second.get(); - if (!m_Archive->WriteString("/") || - !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) { - return false; - } - - if (bSignDict && key == "Contents") - bSignValue = true; - if (!WriteDirectObj(objnum, pValue, !bSignValue)) - return false; - } - if (!m_Archive->WriteString(">>")) - return false; - break; - } - } - return true; -} - bool CPDF_Creator::WriteOldIndirectObject(uint32_t objnum) { if (m_pParser->IsObjectFreeOrNull(objnum)) return true; @@ -583,7 +460,7 @@ CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage4() { !m_Archive->WriteString(PDF_NameEncode(key).AsStringView())) { return Stage::kInvalid; } - if (!pValue->WriteTo(m_Archive.get())) + if (!pValue->WriteTo(m_Archive.get(), nullptr)) return Stage::kInvalid; } } else { @@ -632,7 +509,7 @@ CPDF_Creator::Stage CPDF_Creator::WriteDoc_Stage4() { } if (m_pIDArray) { if (!m_Archive->WriteString(("/ID")) || - !m_pIDArray->WriteTo(m_Archive.get())) { + !m_pIDArray->WriteTo(m_Archive.get(), nullptr)) { return Stage::kInvalid; } } diff --git a/core/fpdfapi/edit/cpdf_creator.h b/core/fpdfapi/edit/cpdf_creator.h index a7261145e9..39e0950af6 100644 --- a/core/fpdfapi/edit/cpdf_creator.h +++ b/core/fpdfapi/edit/cpdf_creator.h @@ -69,11 +69,8 @@ class CPDF_Creator { bool WriteOldIndirectObject(uint32_t objnum); bool WriteOldObjs(); bool WriteNewObjs(); - bool WriteDirectObj(uint32_t objnum, const CPDF_Object* pObj, bool bEncrypt); bool WriteIndirectObj(uint32_t objnum, const CPDF_Object* pObj); - bool WriteStream(const CPDF_Object* pStream, uint32_t objnum); - CPDF_CryptoHandler* GetCryptoHandler(); UnownedPtr<CPDF_Document> const m_pDocument; diff --git a/core/fpdfapi/edit/cpdf_encryptor.cpp b/core/fpdfapi/edit/cpdf_encryptor.cpp index 8994b555ee..c74e53ed75 100644 --- a/core/fpdfapi/edit/cpdf_encryptor.cpp +++ b/core/fpdfapi/edit/cpdf_encryptor.cpp @@ -5,25 +5,27 @@ // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "core/fpdfapi/edit/cpdf_encryptor.h" + #include "core/fpdfapi/parser/cpdf_crypto_handler.h" +#include "third_party/base/ptr_util.h" -CPDF_Encryptor::CPDF_Encryptor(CPDF_CryptoHandler* pHandler, - int objnum, - pdfium::span<const uint8_t> src_data) { - if (src_data.empty()) - return; +CPDF_Encryptor::CPDF_Encryptor(CPDF_CryptoHandler* pHandler, int objnum) + : m_pHandler(pHandler), m_ObjNum(objnum) { + ASSERT(m_pHandler); +} - if (!pHandler) { - m_Span = src_data; - return; - } +std::vector<uint8_t> CPDF_Encryptor::Encrypt( + pdfium::span<const uint8_t> src_data) const { + if (src_data.empty()) + return std::vector<uint8_t>(); - uint32_t buf_size = pHandler->EncryptGetSize(src_data); - m_NewBuf.resize(buf_size); - pHandler->EncryptContent(objnum, 0, src_data, m_NewBuf.data(), - buf_size); // Updates |buf_size| with actual. - m_NewBuf.resize(buf_size); - m_Span = m_NewBuf; + std::vector<uint8_t> result; + uint32_t buf_size = m_pHandler->EncryptGetSize(src_data); + result.resize(buf_size); + m_pHandler->EncryptContent(m_ObjNum, 0, src_data, result.data(), + buf_size); // Updates |buf_size| with actual. + result.resize(buf_size); + return result; } CPDF_Encryptor::~CPDF_Encryptor() {} diff --git a/core/fpdfapi/edit/cpdf_encryptor.h b/core/fpdfapi/edit/cpdf_encryptor.h index 67fd5c4f9b..5486c4f248 100644 --- a/core/fpdfapi/edit/cpdf_encryptor.h +++ b/core/fpdfapi/edit/cpdf_encryptor.h @@ -9,25 +9,25 @@ #include <stdint.h> +#include <memory> #include <vector> #include "core/fxcrt/fx_memory.h" +#include "core/fxcrt/unowned_ptr.h" #include "third_party/base/span.h" class CPDF_CryptoHandler; class CPDF_Encryptor { public: - CPDF_Encryptor(CPDF_CryptoHandler* pHandler, - int objnum, - pdfium::span<const uint8_t> src_data); + CPDF_Encryptor(CPDF_CryptoHandler* pHandler, int objnum); ~CPDF_Encryptor(); - pdfium::span<const uint8_t> GetSpan() const { return m_Span; } + std::vector<uint8_t> Encrypt(pdfium::span<const uint8_t> src_data) const; private: - std::vector<uint8_t> m_NewBuf; - pdfium::span<const uint8_t> m_Span; + UnownedPtr<CPDF_CryptoHandler> const m_pHandler; + const int m_ObjNum; }; #endif // CORE_FPDFAPI_EDIT_CPDF_ENCRYPTOR_H_ diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp index f6a941d200..9693bc48ff 100644 --- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp +++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp @@ -266,7 +266,7 @@ const CPDF_ContentMark* CPDF_PageContentGenerator::ProcessContentMarks( // If there are parameters, write properties, direct or indirect. if (item->GetParamType() == CPDF_ContentMarkItem::DirectDict) { CPDF_StringArchiveStream archive_stream(buf); - item->GetParam()->WriteTo(&archive_stream); + item->GetParam()->WriteTo(&archive_stream, nullptr); *buf << " "; } else { ASSERT(item->GetParamType() == CPDF_ContentMarkItem::PropertiesDict); diff --git a/core/fpdfapi/parser/cpdf_array.cpp b/core/fpdfapi/parser/cpdf_array.cpp index d53476d1c2..68b301e283 100644 --- a/core/fpdfapi/parser/cpdf_array.cpp +++ b/core/fpdfapi/parser/cpdf_array.cpp @@ -230,12 +230,13 @@ CPDF_Object* CPDF_Array::Add(std::unique_ptr<CPDF_Object> pObj) { return pRet; } -bool CPDF_Array::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Array::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { if (!archive->WriteString("[")) return false; for (size_t i = 0; i < GetCount(); ++i) { - if (!GetObjectAt(i)->WriteTo(archive)) + if (!GetObjectAt(i)->WriteTo(archive, encryptor)) return false; } return archive->WriteString("]"); diff --git a/core/fpdfapi/parser/cpdf_array.h b/core/fpdfapi/parser/cpdf_array.h index d980b14507..1e63983d51 100644 --- a/core/fpdfapi/parser/cpdf_array.h +++ b/core/fpdfapi/parser/cpdf_array.h @@ -33,7 +33,8 @@ class CPDF_Array : public CPDF_Object { bool IsArray() const override; CPDF_Array* AsArray() override; const CPDF_Array* AsArray() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) 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 a1dc450519..a26110116b 100644 --- a/core/fpdfapi/parser/cpdf_boolean.cpp +++ b/core/fpdfapi/parser/cpdf_boolean.cpp @@ -46,7 +46,8 @@ const CPDF_Boolean* CPDF_Boolean::AsBoolean() const { return this; } -bool CPDF_Boolean::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Boolean::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { return archive->WriteString(" ") && archive->WriteString(GetString().AsStringView()); } diff --git a/core/fpdfapi/parser/cpdf_boolean.h b/core/fpdfapi/parser/cpdf_boolean.h index c0a69d8932..61c213bdb9 100644 --- a/core/fpdfapi/parser/cpdf_boolean.h +++ b/core/fpdfapi/parser/cpdf_boolean.h @@ -28,7 +28,8 @@ class CPDF_Boolean : public CPDF_Object { bool IsBoolean() const override; CPDF_Boolean* AsBoolean() override; const CPDF_Boolean* AsBoolean() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; protected: bool m_bValue; diff --git a/core/fpdfapi/parser/cpdf_dictionary.cpp b/core/fpdfapi/parser/cpdf_dictionary.cpp index 78227ae70a..585930427c 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.cpp +++ b/core/fpdfapi/parser/cpdf_dictionary.cpp @@ -269,10 +269,13 @@ ByteString CPDF_Dictionary::MaybeIntern(const ByteString& str) { return m_pPool ? m_pPool->Intern(str) : str; } -bool CPDF_Dictionary::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Dictionary::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { if (!archive->WriteString("<<")) return false; + const bool is_signature = CPDF_CryptoHandler::IsSignatureDictionary(this); + for (const auto& it : *this) { const ByteString& key = it.first; CPDF_Object* pValue = it.second.get(); @@ -280,9 +283,11 @@ bool CPDF_Dictionary::WriteTo(IFX_ArchiveStream* archive) const { !archive->WriteString(PDF_NameEncode(key).AsStringView())) { return false; } - - if (!pValue->WriteTo(archive)) + if (!pValue->WriteTo(archive, !is_signature || key != "Contents" + ? encryptor + : nullptr)) { return false; + } } return archive->WriteString(">>"); } diff --git a/core/fpdfapi/parser/cpdf_dictionary.h b/core/fpdfapi/parser/cpdf_dictionary.h index 569baedb0b..5cd0e8be22 100644 --- a/core/fpdfapi/parser/cpdf_dictionary.h +++ b/core/fpdfapi/parser/cpdf_dictionary.h @@ -38,7 +38,8 @@ class CPDF_Dictionary : public CPDF_Object { bool IsDictionary() const override; CPDF_Dictionary* AsDictionary() override; const CPDF_Dictionary* AsDictionary() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; size_t GetCount() const { return m_Map.size(); } const CPDF_Object* GetObjectFor(const ByteString& key) const; diff --git a/core/fpdfapi/parser/cpdf_name.cpp b/core/fpdfapi/parser/cpdf_name.cpp index 59a014208b..d35a76c8a0 100644 --- a/core/fpdfapi/parser/cpdf_name.cpp +++ b/core/fpdfapi/parser/cpdf_name.cpp @@ -51,7 +51,8 @@ WideString CPDF_Name::GetUnicodeText() const { return PDF_DecodeText(m_Name); } -bool CPDF_Name::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Name::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { return archive->WriteString("/") && archive->WriteString(PDF_NameEncode(GetString()).AsStringView()); } diff --git a/core/fpdfapi/parser/cpdf_name.h b/core/fpdfapi/parser/cpdf_name.h index 880c10aedb..eef6bca715 100644 --- a/core/fpdfapi/parser/cpdf_name.h +++ b/core/fpdfapi/parser/cpdf_name.h @@ -27,7 +27,8 @@ class CPDF_Name : public CPDF_Object { bool IsName() const override; CPDF_Name* AsName() override; const CPDF_Name* AsName() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; protected: ByteString m_Name; diff --git a/core/fpdfapi/parser/cpdf_null.cpp b/core/fpdfapi/parser/cpdf_null.cpp index 1074efd863..f94b46778b 100644 --- a/core/fpdfapi/parser/cpdf_null.cpp +++ b/core/fpdfapi/parser/cpdf_null.cpp @@ -18,7 +18,8 @@ std::unique_ptr<CPDF_Object> CPDF_Null::Clone() const { return pdfium::MakeUnique<CPDF_Null>(); } -bool CPDF_Null::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Null::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { return archive->WriteString(" null"); } diff --git a/core/fpdfapi/parser/cpdf_null.h b/core/fpdfapi/parser/cpdf_null.h index 2ec05ec82c..003ad2feee 100644 --- a/core/fpdfapi/parser/cpdf_null.h +++ b/core/fpdfapi/parser/cpdf_null.h @@ -18,7 +18,8 @@ class CPDF_Null : public CPDF_Object { // CPDF_Object. Type GetType() const override; std::unique_ptr<CPDF_Object> Clone() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; bool IsNull() const override; }; diff --git a/core/fpdfapi/parser/cpdf_number.cpp b/core/fpdfapi/parser/cpdf_number.cpp index dac1f40b7f..b75ce0766a 100644 --- a/core/fpdfapi/parser/cpdf_number.cpp +++ b/core/fpdfapi/parser/cpdf_number.cpp @@ -57,7 +57,8 @@ ByteString CPDF_Number::GetString() const { : ByteString::FormatFloat(m_Float); } -bool CPDF_Number::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Number::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { return archive->WriteString(" ") && archive->WriteString(GetString().AsStringView()); } diff --git a/core/fpdfapi/parser/cpdf_number.h b/core/fpdfapi/parser/cpdf_number.h index 661177363b..4681bb216a 100644 --- a/core/fpdfapi/parser/cpdf_number.h +++ b/core/fpdfapi/parser/cpdf_number.h @@ -31,7 +31,8 @@ class CPDF_Number : public CPDF_Object { bool IsNumber() const override; CPDF_Number* AsNumber() override; const CPDF_Number* AsNumber() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) 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 5ff028e9e0..6c6b583963 100644 --- a/core/fpdfapi/parser/cpdf_object.h +++ b/core/fpdfapi/parser/cpdf_object.h @@ -17,6 +17,7 @@ class CPDF_Array; class CPDF_Boolean; class CPDF_Dictionary; +class CPDF_Encryptor; class CPDF_IndirectObjectHolder; class CPDF_Name; class CPDF_Null; @@ -95,7 +96,8 @@ class CPDF_Object { virtual CPDF_String* AsString(); virtual const CPDF_String* AsString() const; - virtual bool WriteTo(IFX_ArchiveStream* archive) const = 0; + virtual bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const = 0; // Create a deep copy of the object with the option to either // copy a reference object or directly copy the object it refers to diff --git a/core/fpdfapi/parser/cpdf_reference.cpp b/core/fpdfapi/parser/cpdf_reference.cpp index 0f3b7627d6..5a4d58a0e2 100644 --- a/core/fpdfapi/parser/cpdf_reference.cpp +++ b/core/fpdfapi/parser/cpdf_reference.cpp @@ -99,7 +99,8 @@ const CPDF_Object* CPDF_Reference::GetDirect() const { : nullptr; } -bool CPDF_Reference::WriteTo(IFX_ArchiveStream* archive) const { +bool CPDF_Reference::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { return archive->WriteString(" ") && archive->WriteDWord(GetRefObjNum()) && archive->WriteString(" 0 R "); } diff --git a/core/fpdfapi/parser/cpdf_reference.h b/core/fpdfapi/parser/cpdf_reference.h index d1e0a07e4b..cdb5d5e674 100644 --- a/core/fpdfapi/parser/cpdf_reference.h +++ b/core/fpdfapi/parser/cpdf_reference.h @@ -33,7 +33,8 @@ class CPDF_Reference : public CPDF_Object { bool IsReference() const override; CPDF_Reference* AsReference() override; const CPDF_Reference* AsReference() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; std::unique_ptr<CPDF_Object> MakeReference( CPDF_IndirectObjectHolder* holder) const override; diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp index fdbe308878..64478996a8 100644 --- a/core/fpdfapi/parser/cpdf_stream.cpp +++ b/core/fpdfapi/parser/cpdf_stream.cpp @@ -7,8 +7,11 @@ #include "core/fpdfapi/parser/cpdf_stream.h" #include <utility> +#include <vector> #include "constants/stream_dict_common.h" +#include "core/fpdfapi/edit/cpdf_encryptor.h" +#include "core/fpdfapi/edit/cpdf_flateencoder.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_number.h" #include "core/fpdfapi/parser/cpdf_stream_acc.h" @@ -18,6 +21,15 @@ #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" +namespace { + +bool IsMetaDataStreamDictionary(const CPDF_Dictionary* dict) { + return dict && dict->GetStringFor("Type") == "Metadata" && + dict->GetStringFor("Subtype") == "XML"; +} + +} // namespace + CPDF_Stream::CPDF_Stream() {} CPDF_Stream::CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData, @@ -167,12 +179,33 @@ WideString CPDF_Stream::GetUnicodeText() const { return PDF_DecodeText(pAcc->GetData(), pAcc->GetSize()); } -bool CPDF_Stream::WriteTo(IFX_ArchiveStream* archive) const { - if (!GetDict()->WriteTo(archive) || !archive->WriteString("stream\r\n")) +bool CPDF_Stream::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { + const bool is_metadata = IsMetaDataStreamDictionary(GetDict()); + CPDF_FlateEncoder encoder(this, !is_metadata); + + std::vector<uint8_t> encrypted_data; + pdfium::span<const uint8_t> data = encoder.GetSpan(); + + if (encryptor && !is_metadata) { + encrypted_data = encryptor->Encrypt(data); + data = encrypted_data; + } + + if (static_cast<uint32_t>(encoder.GetDict()->GetIntegerFor("Length")) != + data.size()) { + encoder.CloneDict(); + encoder.GetClonedDict()->SetNewFor<CPDF_Number>( + "Length", static_cast<int>(data.size())); + } + + if (!encoder.GetDict()->WriteTo(archive, encryptor)) return false; - auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this); - pAcc->LoadAllDataRaw(); - return archive->WriteBlock(pAcc->GetData(), pAcc->GetSize()) && - archive->WriteString("\r\nendstream"); + if (!archive->WriteString("stream\r\n") || + !archive->WriteBlock(data.data(), data.size()) || + !archive->WriteString("\r\nendstream")) { + return false; + } + return true; } diff --git a/core/fpdfapi/parser/cpdf_stream.h b/core/fpdfapi/parser/cpdf_stream.h index 7e98f300ba..4a5ac61011 100644 --- a/core/fpdfapi/parser/cpdf_stream.h +++ b/core/fpdfapi/parser/cpdf_stream.h @@ -34,7 +34,8 @@ class CPDF_Stream : public CPDF_Object { bool IsStream() const override; CPDF_Stream* AsStream() override; const CPDF_Stream* AsStream() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; uint32_t GetRawSize() const { return m_dwSize; } // Will be null in case when stream is not memory based. diff --git a/core/fpdfapi/parser/cpdf_string.cpp b/core/fpdfapi/parser/cpdf_string.cpp index 851442e8b4..e7f2a9dcd6 100644 --- a/core/fpdfapi/parser/cpdf_string.cpp +++ b/core/fpdfapi/parser/cpdf_string.cpp @@ -7,7 +7,9 @@ #include "core/fpdfapi/parser/cpdf_string.h" #include <utility> +#include <vector> +#include "core/fpdfapi/edit/cpdf_encryptor.h" #include "core/fpdfapi/parser/fpdf_parser_decode.h" #include "core/fxcrt/fx_stream.h" #include "third_party/base/ptr_util.h" @@ -65,7 +67,15 @@ WideString CPDF_String::GetUnicodeText() const { return PDF_DecodeText(m_String); } -bool CPDF_String::WriteTo(IFX_ArchiveStream* archive) const { - return archive->WriteString( - PDF_EncodeString(GetString(), IsHex()).AsStringView()); +bool CPDF_String::WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const { + std::vector<uint8_t> encrypted_data; + pdfium::span<const uint8_t> data = m_String.AsRawSpan(); + if (encryptor) { + encrypted_data = encryptor->Encrypt(data); + data = encrypted_data; + } + const ByteString content = + PDF_EncodeString(ByteString(data.data(), data.size()), IsHex()); + return archive->WriteString(content.AsStringView()); } diff --git a/core/fpdfapi/parser/cpdf_string.h b/core/fpdfapi/parser/cpdf_string.h index b6aaacb043..144fe64cba 100644 --- a/core/fpdfapi/parser/cpdf_string.h +++ b/core/fpdfapi/parser/cpdf_string.h @@ -31,7 +31,8 @@ class CPDF_String : public CPDF_Object { bool IsString() const override; CPDF_String* AsString() override; const CPDF_String* AsString() const override; - bool WriteTo(IFX_ArchiveStream* archive) const override; + bool WriteTo(IFX_ArchiveStream* archive, + const CPDF_Encryptor* encryptor) const override; bool IsHex() const { return m_bHex; } |