1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fpdfapi/parser/cpdf_stream.h"
8
9 #include <utility>
10 #include <vector>
11
12 #include "constants/stream_dict_common.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_encryptor.h"
15 #include "core/fpdfapi/parser/cpdf_flateencoder.h"
16 #include "core/fpdfapi/parser/cpdf_number.h"
17 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
18 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
19 #include "core/fxcrt/fx_stream.h"
20 #include "third_party/base/numerics/safe_conversions.h"
21 #include "third_party/base/ptr_util.h"
22 #include "third_party/base/stl_util.h"
23
24 namespace {
25
IsMetaDataStreamDictionary(const CPDF_Dictionary * dict)26 bool IsMetaDataStreamDictionary(const CPDF_Dictionary* dict) {
27 return dict && dict->GetStringFor("Type") == "Metadata" &&
28 dict->GetStringFor("Subtype") == "XML";
29 }
30
31 } // namespace
32
CPDF_Stream()33 CPDF_Stream::CPDF_Stream() {}
34
CPDF_Stream(std::unique_ptr<uint8_t,FxFreeDeleter> pData,uint32_t size,RetainPtr<CPDF_Dictionary> pDict)35 CPDF_Stream::CPDF_Stream(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
36 uint32_t size,
37 RetainPtr<CPDF_Dictionary> pDict)
38 : m_pDict(std::move(pDict)) {
39 TakeData(std::move(pData), size);
40 }
41
~CPDF_Stream()42 CPDF_Stream::~CPDF_Stream() {
43 m_ObjNum = kInvalidObjNum;
44 if (m_pDict && m_pDict->GetObjNum() == kInvalidObjNum)
45 m_pDict.Leak(); // lowercase release, release ownership.
46 }
47
GetType() const48 CPDF_Object::Type CPDF_Stream::GetType() const {
49 return kStream;
50 }
51
GetDict()52 CPDF_Dictionary* CPDF_Stream::GetDict() {
53 return m_pDict.Get();
54 }
55
GetDict() const56 const CPDF_Dictionary* CPDF_Stream::GetDict() const {
57 return m_pDict.Get();
58 }
59
IsStream() const60 bool CPDF_Stream::IsStream() const {
61 return true;
62 }
63
AsStream()64 CPDF_Stream* CPDF_Stream::AsStream() {
65 return this;
66 }
67
AsStream() const68 const CPDF_Stream* CPDF_Stream::AsStream() const {
69 return this;
70 }
71
InitStream(pdfium::span<const uint8_t> pData,RetainPtr<CPDF_Dictionary> pDict)72 void CPDF_Stream::InitStream(pdfium::span<const uint8_t> pData,
73 RetainPtr<CPDF_Dictionary> pDict) {
74 m_pDict = std::move(pDict);
75 SetData(pData);
76 }
77
InitStreamFromFile(const RetainPtr<IFX_SeekableReadStream> & pFile,RetainPtr<CPDF_Dictionary> pDict)78 void CPDF_Stream::InitStreamFromFile(
79 const RetainPtr<IFX_SeekableReadStream>& pFile,
80 RetainPtr<CPDF_Dictionary> pDict) {
81 m_bMemoryBased = false;
82 m_pDataBuf.reset();
83 m_pFile = pFile;
84 m_dwSize = pdfium::base::checked_cast<uint32_t>(pFile->GetSize());
85 m_pDict = std::move(pDict);
86 m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(m_dwSize));
87 }
88
Clone() const89 RetainPtr<CPDF_Object> CPDF_Stream::Clone() const {
90 return CloneObjectNonCyclic(false);
91 }
92
CloneNonCyclic(bool bDirect,std::set<const CPDF_Object * > * pVisited) const93 RetainPtr<CPDF_Object> CPDF_Stream::CloneNonCyclic(
94 bool bDirect,
95 std::set<const CPDF_Object*>* pVisited) const {
96 pVisited->insert(this);
97 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this);
98 pAcc->LoadAllDataRaw();
99
100 uint32_t streamSize = pAcc->GetSize();
101 const CPDF_Dictionary* pDict = GetDict();
102 RetainPtr<CPDF_Dictionary> pNewDict;
103 if (pDict && !pdfium::ContainsKey(*pVisited, pDict)) {
104 pNewDict =
105 ToDictionary(static_cast<const CPDF_Object*>(pDict)->CloneNonCyclic(
106 bDirect, pVisited));
107 }
108 return pdfium::MakeRetain<CPDF_Stream>(pAcc->DetachData(), streamSize,
109 std::move(pNewDict));
110 }
111
SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData)112 void CPDF_Stream::SetDataAndRemoveFilter(pdfium::span<const uint8_t> pData) {
113 SetData(pData);
114 m_pDict->RemoveFor("Filter");
115 m_pDict->RemoveFor(pdfium::stream::kDecodeParms);
116 }
117
SetDataFromStringstreamAndRemoveFilter(std::ostringstream * stream)118 void CPDF_Stream::SetDataFromStringstreamAndRemoveFilter(
119 std::ostringstream* stream) {
120 if (stream->tellp() <= 0) {
121 SetDataAndRemoveFilter({});
122 return;
123 }
124
125 SetDataAndRemoveFilter(
126 {reinterpret_cast<const uint8_t*>(stream->str().c_str()),
127 static_cast<size_t>(stream->tellp())});
128 }
129
SetData(pdfium::span<const uint8_t> pData)130 void CPDF_Stream::SetData(pdfium::span<const uint8_t> pData) {
131 std::unique_ptr<uint8_t, FxFreeDeleter> data_copy;
132 if (!pData.empty()) {
133 data_copy.reset(FX_Alloc(uint8_t, pData.size()));
134 memcpy(data_copy.get(), pData.data(), pData.size());
135 }
136 TakeData(std::move(data_copy), pData.size());
137 }
138
TakeData(std::unique_ptr<uint8_t,FxFreeDeleter> pData,uint32_t size)139 void CPDF_Stream::TakeData(std::unique_ptr<uint8_t, FxFreeDeleter> pData,
140 uint32_t size) {
141 m_bMemoryBased = true;
142 m_pFile = nullptr;
143 m_pDataBuf = std::move(pData);
144 m_dwSize = size;
145 if (!m_pDict)
146 m_pDict = pdfium::MakeRetain<CPDF_Dictionary>();
147 m_pDict->SetNewFor<CPDF_Number>("Length", static_cast<int>(size));
148 }
149
SetDataFromStringstream(std::ostringstream * stream)150 void CPDF_Stream::SetDataFromStringstream(std::ostringstream* stream) {
151 if (stream->tellp() <= 0) {
152 SetData({});
153 return;
154 }
155 SetData({reinterpret_cast<const uint8_t*>(stream->str().c_str()),
156 static_cast<size_t>(stream->tellp())});
157 }
158
ReadRawData(FX_FILESIZE offset,uint8_t * buf,uint32_t size) const159 bool CPDF_Stream::ReadRawData(FX_FILESIZE offset,
160 uint8_t* buf,
161 uint32_t size) const {
162 if (!m_bMemoryBased && m_pFile)
163 return m_pFile->ReadBlockAtOffset(buf, offset, size);
164
165 if (m_pDataBuf)
166 memcpy(buf, m_pDataBuf.get() + offset, size);
167
168 return true;
169 }
170
HasFilter() const171 bool CPDF_Stream::HasFilter() const {
172 return m_pDict && m_pDict->KeyExist("Filter");
173 }
174
GetUnicodeText() const175 WideString CPDF_Stream::GetUnicodeText() const {
176 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(this);
177 pAcc->LoadAllDataFiltered();
178 return PDF_DecodeText(pAcc->GetSpan());
179 }
180
WriteTo(IFX_ArchiveStream * archive,const CPDF_Encryptor * encryptor) const181 bool CPDF_Stream::WriteTo(IFX_ArchiveStream* archive,
182 const CPDF_Encryptor* encryptor) const {
183 const bool is_metadata = IsMetaDataStreamDictionary(GetDict());
184 CPDF_FlateEncoder encoder(this, !is_metadata);
185
186 std::vector<uint8_t> encrypted_data;
187 pdfium::span<const uint8_t> data = encoder.GetSpan();
188
189 if (encryptor && !is_metadata) {
190 encrypted_data = encryptor->Encrypt(data);
191 data = encrypted_data;
192 }
193
194 size_t size = data.size();
195 if (static_cast<size_t>(encoder.GetDict()->GetIntegerFor("Length")) != size) {
196 encoder.CloneDict();
197 encoder.GetClonedDict()->SetNewFor<CPDF_Number>("Length",
198 static_cast<int>(size));
199 }
200
201 if (!encoder.GetDict()->WriteTo(archive, encryptor))
202 return false;
203
204 if (!archive->WriteString("stream\r\n"))
205 return false;
206
207 if (size && !archive->WriteBlock(data.data(), size))
208 return false;
209
210 if (!archive->WriteString("\r\nendstream"))
211 return false;
212
213 return true;
214 }
215