1 // Copyright 2018 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 #include "core/fpdfapi/parser/cpdf_cross_ref_table.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "core/fpdfapi/parser/cpdf_dictionary.h"
11 #include "core/fpdfapi/parser/cpdf_parser.h"
12 #include "third_party/base/stl_util.h"
13
14 // static
MergeUp(std::unique_ptr<CPDF_CrossRefTable> current,std::unique_ptr<CPDF_CrossRefTable> top)15 std::unique_ptr<CPDF_CrossRefTable> CPDF_CrossRefTable::MergeUp(
16 std::unique_ptr<CPDF_CrossRefTable> current,
17 std::unique_ptr<CPDF_CrossRefTable> top) {
18 if (!current)
19 return top;
20
21 if (!top)
22 return current;
23
24 current->Update(std::move(top));
25 return current;
26 }
27
28 CPDF_CrossRefTable::CPDF_CrossRefTable() = default;
29
CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer)30 CPDF_CrossRefTable::CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer)
31 : trailer_(std::move(trailer)) {}
32
33 CPDF_CrossRefTable::~CPDF_CrossRefTable() = default;
34
AddCompressed(uint32_t obj_num,uint32_t archive_obj_num)35 void CPDF_CrossRefTable::AddCompressed(uint32_t obj_num,
36 uint32_t archive_obj_num) {
37 if (obj_num >= CPDF_Parser::kMaxObjectNumber ||
38 archive_obj_num >= CPDF_Parser::kMaxObjectNumber) {
39 NOTREACHED();
40 return;
41 }
42
43 auto& info = objects_info_[obj_num];
44 if (info.gennum > 0)
45 return;
46
47 if (info.type == ObjectType::kObjStream)
48 return;
49
50 info.type = ObjectType::kCompressed;
51 info.archive_obj_num = archive_obj_num;
52 info.gennum = 0;
53
54 objects_info_[archive_obj_num].type = ObjectType::kObjStream;
55 }
56
AddNormal(uint32_t obj_num,uint16_t gen_num,FX_FILESIZE pos)57 void CPDF_CrossRefTable::AddNormal(uint32_t obj_num,
58 uint16_t gen_num,
59 FX_FILESIZE pos) {
60 if (obj_num >= CPDF_Parser::kMaxObjectNumber) {
61 NOTREACHED();
62 return;
63 }
64
65 auto& info = objects_info_[obj_num];
66 if (info.gennum > gen_num)
67 return;
68
69 if (info.type == ObjectType::kCompressed && gen_num == 0)
70 return;
71
72 if (info.type != ObjectType::kObjStream)
73 info.type = ObjectType::kNormal;
74
75 info.gennum = gen_num;
76 info.pos = pos;
77 }
78
SetFree(uint32_t obj_num)79 void CPDF_CrossRefTable::SetFree(uint32_t obj_num) {
80 if (obj_num >= CPDF_Parser::kMaxObjectNumber) {
81 NOTREACHED();
82 return;
83 }
84
85 auto& info = objects_info_[obj_num];
86 info.type = ObjectType::kFree;
87 info.gennum = 0xFFFF;
88 info.pos = 0;
89 }
90
SetTrailer(RetainPtr<CPDF_Dictionary> trailer)91 void CPDF_CrossRefTable::SetTrailer(RetainPtr<CPDF_Dictionary> trailer) {
92 trailer_ = std::move(trailer);
93 }
94
GetObjectInfo(uint32_t obj_num) const95 const CPDF_CrossRefTable::ObjectInfo* CPDF_CrossRefTable::GetObjectInfo(
96 uint32_t obj_num) const {
97 const auto it = objects_info_.find(obj_num);
98 return it != objects_info_.end() ? &it->second : nullptr;
99 }
100
Update(std::unique_ptr<CPDF_CrossRefTable> new_cross_ref)101 void CPDF_CrossRefTable::Update(
102 std::unique_ptr<CPDF_CrossRefTable> new_cross_ref) {
103 UpdateInfo(std::move(new_cross_ref->objects_info_));
104 UpdateTrailer(std::move(new_cross_ref->trailer_));
105 }
106
ShrinkObjectMap(uint32_t objnum)107 void CPDF_CrossRefTable::ShrinkObjectMap(uint32_t objnum) {
108 if (objnum == 0) {
109 objects_info_.clear();
110 return;
111 }
112
113 objects_info_.erase(objects_info_.lower_bound(objnum), objects_info_.end());
114
115 if (!pdfium::ContainsKey(objects_info_, objnum - 1))
116 objects_info_[objnum - 1].pos = 0;
117 }
118
UpdateInfo(std::map<uint32_t,ObjectInfo> && new_objects_info)119 void CPDF_CrossRefTable::UpdateInfo(
120 std::map<uint32_t, ObjectInfo>&& new_objects_info) {
121 auto cur_it = objects_info_.begin();
122 auto new_it = new_objects_info.begin();
123 while (cur_it != objects_info_.end() && new_it != new_objects_info.end()) {
124 if (cur_it->first == new_it->first) {
125 if (cur_it->second.type == ObjectType::kObjStream &&
126 new_it->second.type == ObjectType::kNormal) {
127 new_it->second.type = ObjectType::kObjStream;
128 }
129 ++cur_it;
130 ++new_it;
131 } else if (cur_it->first < new_it->first) {
132 new_objects_info.insert(new_it, *cur_it);
133 ++cur_it;
134 } else {
135 new_it = new_objects_info.lower_bound(cur_it->first);
136 }
137 }
138 for (; cur_it != objects_info_.end(); ++cur_it) {
139 new_objects_info.insert(new_objects_info.end(), *cur_it);
140 }
141 objects_info_ = std::move(new_objects_info);
142 }
143
UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer)144 void CPDF_CrossRefTable::UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer) {
145 if (!new_trailer)
146 return;
147
148 if (!trailer_) {
149 trailer_ = std::move(new_trailer);
150 return;
151 }
152
153 new_trailer->SetFor("XRefStm", trailer_->RemoveFor("XRefStm"));
154 new_trailer->SetFor("Prev", trailer_->RemoveFor("Prev"));
155
156 for (const auto& key : new_trailer->GetKeys())
157 trailer_->SetFor(key, new_trailer->RemoveFor(key));
158 }
159