• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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