• 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 "core/fxcrt/check_op.h"
12 #include "core/fxcrt/containers/contains.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   CHECK_LT(obj_num, CPDF_Parser::kMaxObjectNumber);
41   CHECK_LT(archive_obj_num, CPDF_Parser::kMaxObjectNumber);
42 
43   auto& info = objects_info_[obj_num];
44   if (info.gennum > 0)
45     return;
46 
47   // Don't add known object streams to object streams.
48   if (info.is_object_stream_flag) {
49     return;
50   }
51 
52   info.type = ObjectType::kCompressed;
53   info.archive.obj_num = archive_obj_num;
54   info.archive.obj_index = archive_obj_index;
55   info.gennum = 0;
56 
57   objects_info_[archive_obj_num].is_object_stream_flag = true;
58 }
59 
AddNormal(uint32_t obj_num,uint16_t gen_num,bool is_object_stream,FX_FILESIZE pos)60 void CPDF_CrossRefTable::AddNormal(uint32_t obj_num,
61                                    uint16_t gen_num,
62                                    bool is_object_stream,
63                                    FX_FILESIZE pos) {
64   CHECK_LT(obj_num, CPDF_Parser::kMaxObjectNumber);
65 
66   auto& info = objects_info_[obj_num];
67   if (info.gennum > gen_num)
68     return;
69 
70   info.type = ObjectType::kNormal;
71   info.is_object_stream_flag |= is_object_stream;
72   info.gennum = gen_num;
73   info.pos = pos;
74 }
75 
SetFree(uint32_t obj_num,uint16_t gen_num)76 void CPDF_CrossRefTable::SetFree(uint32_t obj_num, uint16_t gen_num) {
77   CHECK_LT(obj_num, CPDF_Parser::kMaxObjectNumber);
78 
79   auto& info = objects_info_[obj_num];
80   info.type = ObjectType::kFree;
81   info.gennum = gen_num;
82   info.pos = 0;
83 }
84 
SetTrailer(RetainPtr<CPDF_Dictionary> trailer,uint32_t trailer_object_number)85 void CPDF_CrossRefTable::SetTrailer(RetainPtr<CPDF_Dictionary> trailer,
86                                     uint32_t trailer_object_number) {
87   trailer_ = std::move(trailer);
88   trailer_object_number_ = trailer_object_number;
89 }
90 
GetObjectInfo(uint32_t obj_num) const91 const CPDF_CrossRefTable::ObjectInfo* CPDF_CrossRefTable::GetObjectInfo(
92     uint32_t obj_num) const {
93   const auto it = objects_info_.find(obj_num);
94   return it != objects_info_.end() ? &it->second : nullptr;
95 }
96 
Update(std::unique_ptr<CPDF_CrossRefTable> new_cross_ref)97 void CPDF_CrossRefTable::Update(
98     std::unique_ptr<CPDF_CrossRefTable> new_cross_ref) {
99   UpdateInfo(std::move(new_cross_ref->objects_info_));
100   UpdateTrailer(std::move(new_cross_ref->trailer_));
101 }
102 
SetObjectMapSize(uint32_t size)103 void CPDF_CrossRefTable::SetObjectMapSize(uint32_t size) {
104   if (size == 0) {
105     objects_info_.clear();
106     return;
107   }
108 
109   objects_info_.erase(objects_info_.lower_bound(size), objects_info_.end());
110 
111   if (!pdfium::Contains(objects_info_, size - 1)) {
112     objects_info_[size - 1].pos = 0;
113   }
114 }
115 
UpdateInfo(std::map<uint32_t,ObjectInfo> new_objects_info)116 void CPDF_CrossRefTable::UpdateInfo(
117     std::map<uint32_t, ObjectInfo> new_objects_info) {
118   if (new_objects_info.empty()) {
119     return;
120   }
121 
122   if (objects_info_.empty()) {
123     objects_info_ = std::move(new_objects_info);
124     return;
125   }
126 
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 (new_it->second.type == ObjectType::kNormal &&
132           cur_it->second.type == ObjectType::kNormal &&
133           cur_it->second.is_object_stream_flag) {
134         new_it->second.is_object_stream_flag = true;
135       }
136       ++cur_it;
137       ++new_it;
138     } else if (cur_it->first < new_it->first) {
139       new_objects_info.insert(new_it, *cur_it);
140       ++cur_it;
141     } else {
142       new_it = new_objects_info.lower_bound(cur_it->first);
143     }
144   }
145   for (; cur_it != objects_info_.end(); ++cur_it) {
146     new_objects_info.insert(new_objects_info.end(), *cur_it);
147   }
148   objects_info_ = std::move(new_objects_info);
149 }
150 
UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer)151 void CPDF_CrossRefTable::UpdateTrailer(RetainPtr<CPDF_Dictionary> new_trailer) {
152   if (!new_trailer)
153     return;
154 
155   if (!trailer_) {
156     trailer_ = std::move(new_trailer);
157     return;
158   }
159 
160   new_trailer->SetFor("XRefStm", trailer_->RemoveFor("XRefStm"));
161   new_trailer->SetFor("Prev", trailer_->RemoveFor("Prev"));
162 
163   for (const auto& key : new_trailer->GetKeys())
164     trailer_->SetFor(key, new_trailer->RemoveFor(key.AsStringView()));
165 }
166