• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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