• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ShrinkObjectMap(uint32_t objnum)113 void CPDF_CrossRefTable::ShrinkObjectMap(uint32_t objnum) {
114   if (objnum == 0) {
115     objects_info_.clear();
116     return;
117   }
118 
119   objects_info_.erase(objects_info_.lower_bound(objnum), objects_info_.end());
120 
121   if (!pdfium::Contains(objects_info_, objnum - 1))
122     objects_info_[objnum - 1].pos = 0;
123 }
124 
UpdateInfo(std::map<uint32_t,ObjectInfo> && new_objects_info)125 void CPDF_CrossRefTable::UpdateInfo(
126     std::map<uint32_t, ObjectInfo>&& new_objects_info) {
127   auto cur_it = objects_info_.begin();
128   auto new_it = new_objects_info.begin();
129   while (cur_it != objects_info_.end() && new_it != new_objects_info.end()) {
130     if (cur_it->first == new_it->first) {
131       if (cur_it->second.type == ObjectType::kObjStream &&
132           new_it->second.type == ObjectType::kNormal) {
133         new_it->second.type = ObjectType::kObjStream;
134       }
135       ++cur_it;
136       ++new_it;
137     } else if (cur_it->first < new_it->first) {
138       new_objects_info.insert(new_it, *cur_it);
139       ++cur_it;
140     } else {
141       new_it = new_objects_info.lower_bound(cur_it->first);
142     }
143   }
144   for (; cur_it != objects_info_.end(); ++cur_it) {
145     new_objects_info.insert(new_objects_info.end(), *cur_it);
146   }
147   objects_info_ = std::move(new_objects_info);
148 }
149 
UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer)150 void CPDF_CrossRefTable::UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer) {
151   if (!new_trailer)
152     return;
153 
154   if (!trailer_) {
155     trailer_ = std::move(new_trailer);
156     return;
157   }
158 
159   new_trailer->SetFor("XRefStm", trailer_->RemoveFor("XRefStm"));
160   new_trailer->SetFor("Prev", trailer_->RemoveFor("Prev"));
161 
162   for (const auto& key : new_trailer->GetKeys())
163     trailer_->SetFor(key, new_trailer->RemoveFor(key.AsStringView()));
164 }
165