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_dictionary.h"
8
9#include <set>
10#include <utility>
11
12#include "core/fpdfapi/parser/cpdf_array.h"
13#include "core/fpdfapi/parser/cpdf_boolean.h"
14#include "core/fpdfapi/parser/cpdf_name.h"
15#include "core/fpdfapi/parser/cpdf_number.h"
16#include "core/fpdfapi/parser/cpdf_reference.h"
17#include "core/fpdfapi/parser/cpdf_stream.h"
18#include "core/fpdfapi/parser/cpdf_string.h"
19#include "third_party/base/logging.h"
20#include "third_party/base/stl_util.h"
21
22CPDF_Dictionary::CPDF_Dictionary()
23    : CPDF_Dictionary(CFX_WeakPtr<CFX_ByteStringPool>()) {}
24
25CPDF_Dictionary::CPDF_Dictionary(const CFX_WeakPtr<CFX_ByteStringPool>& pPool)
26    : m_pPool(pPool) {}
27
28CPDF_Dictionary::~CPDF_Dictionary() {
29  // Mark the object as deleted so that it will not be deleted again,
30  // and break cyclic references.
31  m_ObjNum = kInvalidObjNum;
32  for (auto& it : m_Map) {
33    if (it.second && it.second->GetObjNum() == kInvalidObjNum)
34      it.second.release();
35  }
36}
37
38CPDF_Object::Type CPDF_Dictionary::GetType() const {
39  return DICTIONARY;
40}
41
42CPDF_Dictionary* CPDF_Dictionary::GetDict() const {
43  // The method should be made non-const if we want to not be const.
44  // See bug #234.
45  return const_cast<CPDF_Dictionary*>(this);
46}
47
48bool CPDF_Dictionary::IsDictionary() const {
49  return true;
50}
51
52CPDF_Dictionary* CPDF_Dictionary::AsDictionary() {
53  return this;
54}
55
56const CPDF_Dictionary* CPDF_Dictionary::AsDictionary() const {
57  return this;
58}
59
60std::unique_ptr<CPDF_Object> CPDF_Dictionary::Clone() const {
61  return CloneObjectNonCyclic(false);
62}
63
64std::unique_ptr<CPDF_Object> CPDF_Dictionary::CloneNonCyclic(
65    bool bDirect,
66    std::set<const CPDF_Object*>* pVisited) const {
67  pVisited->insert(this);
68  auto pCopy = pdfium::MakeUnique<CPDF_Dictionary>(m_pPool);
69  for (const auto& it : *this) {
70    if (!pdfium::ContainsKey(*pVisited, it.second.get())) {
71      pCopy->m_Map.insert(std::make_pair(
72          it.first, it.second->CloneNonCyclic(bDirect, pVisited)));
73    }
74  }
75  return std::move(pCopy);
76}
77
78CPDF_Object* CPDF_Dictionary::GetObjectFor(const CFX_ByteString& key) const {
79  auto it = m_Map.find(key);
80  return it != m_Map.end() ? it->second.get() : nullptr;
81}
82
83CPDF_Object* CPDF_Dictionary::GetDirectObjectFor(
84    const CFX_ByteString& key) const {
85  CPDF_Object* p = GetObjectFor(key);
86  return p ? p->GetDirect() : nullptr;
87}
88
89CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key) const {
90  CPDF_Object* p = GetObjectFor(key);
91  return p ? p->GetString() : CFX_ByteString();
92}
93
94CFX_WideString CPDF_Dictionary::GetUnicodeTextFor(
95    const CFX_ByteString& key) const {
96  CPDF_Object* p = GetObjectFor(key);
97  if (CPDF_Reference* pRef = ToReference(p))
98    p = pRef->GetDirect();
99  return p ? p->GetUnicodeText() : CFX_WideString();
100}
101
102CFX_ByteString CPDF_Dictionary::GetStringFor(const CFX_ByteString& key,
103                                             const CFX_ByteString& def) const {
104  CPDF_Object* p = GetObjectFor(key);
105  return p ? p->GetString() : CFX_ByteString(def);
106}
107
108int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key) const {
109  CPDF_Object* p = GetObjectFor(key);
110  return p ? p->GetInteger() : 0;
111}
112
113int CPDF_Dictionary::GetIntegerFor(const CFX_ByteString& key, int def) const {
114  CPDF_Object* p = GetObjectFor(key);
115  return p ? p->GetInteger() : def;
116}
117
118FX_FLOAT CPDF_Dictionary::GetNumberFor(const CFX_ByteString& key) const {
119  CPDF_Object* p = GetObjectFor(key);
120  return p ? p->GetNumber() : 0;
121}
122
123bool CPDF_Dictionary::GetBooleanFor(const CFX_ByteString& key,
124                                    bool bDefault) const {
125  CPDF_Object* p = GetObjectFor(key);
126  return ToBoolean(p) ? p->GetInteger() != 0 : bDefault;
127}
128
129CPDF_Dictionary* CPDF_Dictionary::GetDictFor(const CFX_ByteString& key) const {
130  CPDF_Object* p = GetDirectObjectFor(key);
131  if (!p)
132    return nullptr;
133  if (CPDF_Dictionary* pDict = p->AsDictionary())
134    return pDict;
135  if (CPDF_Stream* pStream = p->AsStream())
136    return pStream->GetDict();
137  return nullptr;
138}
139
140CPDF_Array* CPDF_Dictionary::GetArrayFor(const CFX_ByteString& key) const {
141  return ToArray(GetDirectObjectFor(key));
142}
143
144CPDF_Stream* CPDF_Dictionary::GetStreamFor(const CFX_ByteString& key) const {
145  return ToStream(GetDirectObjectFor(key));
146}
147
148CFX_FloatRect CPDF_Dictionary::GetRectFor(const CFX_ByteString& key) const {
149  CFX_FloatRect rect;
150  CPDF_Array* pArray = GetArrayFor(key);
151  if (pArray)
152    rect = pArray->GetRect();
153  return rect;
154}
155
156CFX_Matrix CPDF_Dictionary::GetMatrixFor(const CFX_ByteString& key) const {
157  CFX_Matrix matrix;
158  CPDF_Array* pArray = GetArrayFor(key);
159  if (pArray)
160    matrix = pArray->GetMatrix();
161  return matrix;
162}
163
164bool CPDF_Dictionary::KeyExist(const CFX_ByteString& key) const {
165  return pdfium::ContainsKey(m_Map, key);
166}
167
168bool CPDF_Dictionary::IsSignatureDict() const {
169  CPDF_Object* pType = GetDirectObjectFor("Type");
170  if (!pType)
171    pType = GetDirectObjectFor("FT");
172  return pType && pType->GetString() == "Sig";
173}
174
175CPDF_Object* CPDF_Dictionary::SetFor(const CFX_ByteString& key,
176                                     std::unique_ptr<CPDF_Object> pObj) {
177  if (!pObj) {
178    m_Map.erase(key);
179    return nullptr;
180  }
181  ASSERT(pObj->IsInline());
182  CPDF_Object* pRet = pObj.get();
183  m_Map[MaybeIntern(key)] = std::move(pObj);
184  return pRet;
185}
186
187void CPDF_Dictionary::ConvertToIndirectObjectFor(
188    const CFX_ByteString& key,
189    CPDF_IndirectObjectHolder* pHolder) {
190  auto it = m_Map.find(key);
191  if (it == m_Map.end() || it->second->IsReference())
192    return;
193
194  CPDF_Object* pObj = pHolder->AddIndirectObject(std::move(it->second));
195  it->second = pdfium::MakeUnique<CPDF_Reference>(pHolder, pObj->GetObjNum());
196}
197
198void CPDF_Dictionary::RemoveFor(const CFX_ByteString& key) {
199  m_Map.erase(key);
200}
201
202void CPDF_Dictionary::ReplaceKey(const CFX_ByteString& oldkey,
203                                 const CFX_ByteString& newkey) {
204  auto old_it = m_Map.find(oldkey);
205  if (old_it == m_Map.end())
206    return;
207
208  auto new_it = m_Map.find(newkey);
209  if (new_it == old_it)
210    return;
211
212  m_Map[MaybeIntern(newkey)] = std::move(old_it->second);
213  m_Map.erase(old_it);
214}
215
216void CPDF_Dictionary::SetRectFor(const CFX_ByteString& key,
217                                 const CFX_FloatRect& rect) {
218  CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
219  pArray->AddNew<CPDF_Number>(rect.left);
220  pArray->AddNew<CPDF_Number>(rect.bottom);
221  pArray->AddNew<CPDF_Number>(rect.right);
222  pArray->AddNew<CPDF_Number>(rect.top);
223}
224
225void CPDF_Dictionary::SetMatrixFor(const CFX_ByteString& key,
226                                   const CFX_Matrix& matrix) {
227  CPDF_Array* pArray = SetNewFor<CPDF_Array>(key);
228  pArray->AddNew<CPDF_Number>(matrix.a);
229  pArray->AddNew<CPDF_Number>(matrix.b);
230  pArray->AddNew<CPDF_Number>(matrix.c);
231  pArray->AddNew<CPDF_Number>(matrix.d);
232  pArray->AddNew<CPDF_Number>(matrix.e);
233  pArray->AddNew<CPDF_Number>(matrix.f);
234}
235
236CFX_ByteString CPDF_Dictionary::MaybeIntern(const CFX_ByteString& str) {
237  return m_pPool ? m_pPool->Intern(str) : str;
238}
239