Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cpdf_pageorganizer.cpp
Go to the documentation of this file.
1// Copyright 2024 The PDFium Authors
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/edit/cpdf_pageorganizer.h"
8
9#include <utility>
10#include <vector>
11
12#include "constants/page_object.h"
13#include "core/fpdfapi/parser/cpdf_array.h"
14#include "core/fpdfapi/parser/cpdf_dictionary.h"
15#include "core/fpdfapi/parser/cpdf_document.h"
16#include "core/fpdfapi/parser/cpdf_name.h"
17#include "core/fpdfapi/parser/cpdf_number.h"
18#include "core/fpdfapi/parser/cpdf_object.h"
19#include "core/fpdfapi/parser/cpdf_reference.h"
20#include "core/fpdfapi/parser/cpdf_stream.h"
21#include "core/fpdfapi/parser/cpdf_string.h"
22#include "core/fxcrt/bytestring.h"
23#include "core/fxcrt/check.h"
24
28
30
32 DCHECK(dest_doc_);
33 DCHECK(src_doc_);
34
35 return InitDestDoc();
36}
37
38bool CPDF_PageOrganizer::InitDestDoc() {
39 RetainPtr<CPDF_Dictionary> root = dest()->GetMutableRoot();
40 if (!root) {
41 return false;
42 }
43
44 RetainPtr<CPDF_Dictionary> info = dest()->GetInfo();
45 if (info) {
46 info->SetNewFor<CPDF_String>("Producer", "PDFium");
47 }
48
49 if (root->GetByteStringFor("Type", ByteString()).IsEmpty()) {
50 root->SetNewFor<CPDF_Name>("Type", "Catalog");
51 }
52
54 if (RetainPtr<CPDF_Object> current_pages = root->GetMutableObjectFor("Pages");
55 current_pages) {
56 pages = ToDictionary(current_pages->GetMutableDirect());
57 }
58 if (!pages) {
59 pages = dest()->NewIndirect<CPDF_Dictionary>();
60 root->SetNewFor<CPDF_Reference>("Pages", dest(), pages->GetObjNum());
61 }
62 if (pages->GetByteStringFor("Type", ByteString()).IsEmpty()) {
63 pages->SetNewFor<CPDF_Name>("Type", "Pages");
64 }
65
66 if (!pages->GetArrayFor("Kids")) {
67 auto kids_array = dest()->NewIndirect<CPDF_Array>();
68 pages->SetNewFor<CPDF_Number>("Count", 0);
69 pages->SetNewFor<CPDF_Reference>("Kids", dest(), kids_array->GetObjNum());
70 }
71 return true;
72}
73
75 switch (obj->GetType()) {
77 CPDF_Reference* reference = obj->AsMutableReference();
78 uint32_t newobjnum = GetNewObjId(reference);
79 if (newobjnum == 0) {
80 return false;
81 }
82 reference->SetRef(dest(), newobjnum);
83 return true;
84 }
86 CPDF_Dictionary* dict = obj->AsMutableDictionary();
87 std::vector<ByteString> bad_keys;
88 {
89 CPDF_DictionaryLocker locker(dict);
90 for (const auto& it : locker) {
91 const ByteString& key = it.first;
92 if (key == "Parent" || key == "Prev" || key == "First") {
93 continue;
94 }
95 RetainPtr<CPDF_Object> next_obj = it.second;
96 if (!UpdateReference(next_obj)) {
97 bad_keys.push_back(key);
98 }
99 }
100 }
101 for (const auto& key : bad_keys) {
102 dict->RemoveFor(key.AsStringView());
103 }
104 return true;
105 }
106 case CPDF_Object::kArray: {
107 CPDF_Array* array = obj->AsMutableArray();
108 for (size_t i = 0; i < array->size(); ++i) {
109 if (!UpdateReference(array->GetMutableObjectAt(i))) {
110 return false;
111 }
112 }
113 return true;
114 }
116 return UpdateReference(obj->AsMutableStream()->GetMutableDict());
117 }
118 default:
119 return true;
120 }
121}
122
123uint32_t CPDF_PageOrganizer::GetNewObjId(CPDF_Reference* ref) {
124 if (!ref) {
125 return 0;
126 }
127
128 uint32_t obj_num = ref->GetRefObjNum();
129 uint32_t new_obj_num = 0;
130 const auto it = object_number_map_.find(obj_num);
131 if (it != object_number_map_.end()) {
132 new_obj_num = it->second;
133 }
134 if (new_obj_num) {
135 return new_obj_num;
136 }
137
138 RetainPtr<const CPDF_Object> direct = ref->GetDirect();
139 if (!direct) {
140 return 0;
141 }
142
143 RetainPtr<CPDF_Object> clone = direct->Clone();
144 const CPDF_Dictionary* dict_clone = clone->AsDictionary();
145 if (dict_clone && dict_clone->KeyExist("Type")) {
146 ByteString type = dict_clone->GetByteStringFor("Type");
147 if (type.EqualNoCase("Pages")) {
148 return 4;
149 }
150 if (type.EqualNoCase("Page")) {
151 return 0;
152 }
153 }
154
155 new_obj_num = dest()->AddIndirectObject(clone);
156 AddObjectMapping(obj_num, new_obj_num);
157 if (!UpdateReference(std::move(clone))) {
158 return 0;
159 }
160
161 return new_obj_num;
162}
163
164// static
166 RetainPtr<CPDF_Dictionary> dest_page_dict,
167 RetainPtr<const CPDF_Dictionary> src_page_dict,
168 const ByteString& key) {
169 if (dest_page_dict->KeyExist(key)) {
170 return true;
171 }
172
173 RetainPtr<const CPDF_Object> inheritable =
174 PageDictGetInheritableTag(std::move(src_page_dict), key);
175 if (!inheritable) {
176 return false;
177 }
178
179 dest_page_dict->SetFor(key, inheritable->Clone());
180 return true;
181}
182
183// static
185 RetainPtr<const CPDF_Dictionary> dict,
186 const ByteString& src_tag) {
187 if (!dict || src_tag.IsEmpty()) {
188 return nullptr;
189 }
190 if (!dict->KeyExist(pdfium::page_object::kParent) ||
191 !dict->KeyExist(pdfium::page_object::kType)) {
192 return nullptr;
193 }
194
195 RetainPtr<const CPDF_Name> name =
196 ToName(dict->GetObjectFor(pdfium::page_object::kType)->GetDirect());
197 if (!name || name->GetString() != "Page") {
198 return nullptr;
199 }
200
201 RetainPtr<const CPDF_Dictionary> pp = ToDictionary(
202 dict->GetObjectFor(pdfium::page_object::kParent)->GetDirect());
203 if (!pp) {
204 return nullptr;
205 }
206
207 if (dict->KeyExist(src_tag)) {
208 return dict->GetObjectFor(src_tag);
209 }
210
211 while (pp) {
212 if (pp->KeyExist(src_tag)) {
213 return pp->GetObjectFor(src_tag);
214 }
215 if (!pp->KeyExist(pdfium::page_object::kParent)) {
216 break;
217 }
218
219 pp = ToDictionary(
220 pp->GetObjectFor(pdfium::page_object::kParent)->GetDirect());
221 }
222 return nullptr;
223}
fxcrt::ByteString ByteString
Definition bytestring.h:180
#define DCHECK
Definition check.h:33
std::vector< RetainPtr< CPDF_Object > >::const_iterator const_iterator
Definition cpdf_array.h:29
CPDF_DictionaryLocker(const CPDF_Dictionary *pDictionary)
bool KeyExist(const ByteString &key) const
ByteString GetByteStringFor(const ByteString &key) const
std::map< ByteString, RetainPtr< CPDF_Object >, std::less<> > DictMap
uint32_t AddIndirectObject(RetainPtr< CPDF_Object > pObj)
static bool CopyInheritable(RetainPtr< CPDF_Dictionary > dest_page_dict, RetainPtr< const CPDF_Dictionary > src_page_dict, const ByteString &key)
CPDF_Document * dest()
static RetainPtr< const CPDF_Object > PageDictGetInheritableTag(RetainPtr< const CPDF_Dictionary > dict, const ByteString &src_tag)
CPDF_PageOrganizer(CPDF_Document *dest_doc, CPDF_Document *src_doc)
bool UpdateReference(RetainPtr< CPDF_Object > obj)
void AddObjectMapping(uint32_t old_page_obj_num, uint32_t new_page_obj_num)
void SetRef(CPDF_IndirectObjectHolder *pDoc, uint32_t objnum)
uint32_t GetRefObjNum() const
bool EqualNoCase(ByteStringView str) const
ByteString()=default
const char kParent[]