xref: /aosp_15_r20/external/pdfium/core/fpdfapi/parser/cpdf_cross_ref_table.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2018 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 #include "core/fpdfapi/parser/cpdf_cross_ref_table.h"
6 
7 #include <utility>
8 
9 #include "core/fpdfapi/parser/cpdf_dictionary.h"
10 #include "core/fpdfapi/parser/cpdf_parser.h"
11 #include "third_party/base/containers/contains.h"
12 #include "third_party/base/notreached.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,uint32_t trailer_object_number)30 CPDF_CrossRefTable::CPDF_CrossRefTable(RetainPtr<CPDF_Dictionary> trailer,
31                                        uint32_t trailer_object_number)
32     : trailer_(std::move(trailer)),
33       trailer_object_number_(trailer_object_number) {}
34 
35 CPDF_CrossRefTable::~CPDF_CrossRefTable() = default;
36 
AddCompressed(uint32_t obj_num,uint32_t archive_obj_num,uint32_t archive_obj_index)37 void CPDF_CrossRefTable::AddCompressed(uint32_t obj_num,
38                                        uint32_t archive_obj_num,
39                                        uint32_t archive_obj_index) {
40   if (obj_num >= CPDF_Parser::kMaxObjectNumber ||
41       archive_obj_num >= CPDF_Parser::kMaxObjectNumber) {
42     NOTREACHED();
43     return;
44   }
45 
46   auto& info = objects_info_[obj_num];
47   if (info.gennum > 0)
48     return;
49 
50   if (info.type == ObjectType::kObjStream)
51     return;
52 
53   info.type = ObjectType::kCompressed;
54   info.archive.obj_num = archive_obj_num;
55   info.archive.obj_index = archive_obj_index;
56   info.gennum = 0;
57 
58   objects_info_[archive_obj_num].type = ObjectType::kObjStream;
59 }
60 
AddNormal(uint32_t obj_num,uint16_t gen_num,FX_FILESIZE pos)61 void CPDF_CrossRefTable::AddNormal(uint32_t obj_num,
62                                    uint16_t gen_num,
63                                    FX_FILESIZE pos) {
64   if (obj_num >= CPDF_Parser::kMaxObjectNumber) {
65     NOTREACHED();
66     return;
67   }
68 
69   auto& info = objects_info_[obj_num];
70   if (info.gennum > gen_num)
71     return;
72 
73   if (info.type == ObjectType::kCompressed && gen_num == 0)
74     return;
75 
76   if (info.type != ObjectType::kObjStream)
77     info.type = ObjectType::kNormal;
78 
79   info.gennum = gen_num;
80   info.pos = pos;
81 }
82 
SetFree(uint32_t obj_num)83 void CPDF_CrossRefTable::SetFree(uint32_t obj_num) {
84   if (obj_num >= CPDF_Parser::kMaxObjectNumber) {
85     NOTREACHED();
86     return;
87   }
88 
89   auto& info = objects_info_[obj_num];
90   info.type = ObjectType::kFree;
91   info.gennum = 0xFFFF;
92   info.pos = 0;
93 }
94 
SetTrailer(RetainPtr<CPDF_Dictionary> trailer,uint32_t trailer_object_number)95 void CPDF_CrossRefTable::SetTrailer(RetainPtr<CPDF_Dictionary> trailer,
96                                     uint32_t trailer_object_number) {
97   trailer_ = std::move(trailer);
98   trailer_object_number_ = trailer_object_number;
99 }
100 
GetObjectInfo(uint32_t obj_num) const101 const CPDF_CrossRefTable::ObjectInfo* CPDF_CrossRefTable::GetObjectInfo(
102     uint32_t obj_num) const {
103   const auto it = objects_info_.find(obj_num);
104   return it != objects_info_.end() ? &it->second : nullptr;
105 }
106 
Update(std::unique_ptr<CPDF_CrossRefTable> new_cross_ref)107 void CPDF_CrossRefTable::Update(
108     std::unique_ptr<CPDF_CrossRefTable> new_cross_ref) {
109   UpdateInfo(std::move(new_cross_ref->objects_info_));
110   UpdateTrailer(std::move(new_cross_ref->trailer_));
111 }
112 
SetObjectMapSize(uint32_t size)113 void CPDF_CrossRefTable::SetObjectMapSize(uint32_t size) {
114   if (size == 0) {
115     objects_info_.clear();
116     return;
117   }
118 
119   objects_info_.erase(objects_info_.lower_bound(size), objects_info_.end());
120 
121   if (!pdfium::Contains(objects_info_, size - 1)) {
122     objects_info_[size - 1].pos = 0;
123   }
124 }
125 
UpdateInfo(std::map<uint32_t,ObjectInfo> new_objects_info)126 void CPDF_CrossRefTable::UpdateInfo(
127     std::map<uint32_t, ObjectInfo> new_objects_info) {
128   if (new_objects_info.empty()) {
129     return;
130   }
131 
132   if (objects_info_.empty()) {
133     objects_info_ = std::move(new_objects_info);
134     return;
135   }
136 
137   auto cur_it = objects_info_.begin();
138   auto new_it = new_objects_info.begin();
139   while (cur_it != objects_info_.end() && new_it != new_objects_info.end()) {
140     if (cur_it->first == new_it->first) {
141       if (cur_it->second.type == ObjectType::kObjStream &&
142           new_it->second.type == ObjectType::kNormal) {
143         new_it->second.type = ObjectType::kObjStream;
144       }
145       ++cur_it;
146       ++new_it;
147     } else if (cur_it->first < new_it->first) {
148       new_objects_info.insert(new_it, *cur_it);
149       ++cur_it;
150     } else {
151       new_it = new_objects_info.lower_bound(cur_it->first);
152     }
153   }
154   for (; cur_it != objects_info_.end(); ++cur_it) {
155     new_objects_info.insert(new_objects_info.end(), *cur_it);
156   }
157   objects_info_ = std::move(new_objects_info);
158 }
159 
UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer)160 void CPDF_CrossRefTable::UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer) {
161   if (!new_trailer)
162     return;
163 
164   if (!trailer_) {
165     trailer_ = std::move(new_trailer);
166     return;
167   }
168 
169   new_trailer->SetFor("XRefStm", trailer_->RemoveFor("XRefStm"));
170   new_trailer->SetFor("Prev", trailer_->RemoveFor("Prev"));
171 
172   for (const auto& key : new_trailer->GetKeys())
173     trailer_->SetFor(key, new_trailer->RemoveFor(key.AsStringView()));
174 }
175