5#include "core/fpdfapi/parser/object_tree_traversal_util.h"
15#include "core/fpdfapi/parser/cpdf_array.h"
16#include "core/fpdfapi/parser/cpdf_dictionary.h"
17#include "core/fpdfapi/parser/cpdf_document.h"
18#include "core/fpdfapi/parser/cpdf_reference.h"
19#include "core/fpdfapi/parser/cpdf_stream.h"
20#include "core/fxcrt/unowned_ptr.h"
21#include "third_party/base/check.h"
22#include "third_party/base/containers/contains.h"
26class ObjectTreeTraverser {
29 : document_(document) {
31 const CPDF_Dictionary* trailer = parser ? parser
->GetTrailer() :
nullptr;
32 const CPDF_Dictionary* root = trailer ? trailer : document_->GetRoot();
33 const uint32_t root_object_number =
37 if (root_object_number) {
38 referenced_objects_[root_object_number] = 1;
39 object_number_map_[root] = root_object_number;
42 object_queue_.push(pdfium::WrapRetain(root));
43 seen_objects_.insert(root);
45 ~ObjectTreeTraverser() =
default;
47 void Traverse() { CalculateReferenceCounts(GetReferenceEntries()); }
49 const std::map<uint32_t,
int>& referenced_objects() {
50 return referenced_objects_;
54 struct ReferenceEntry {
55 uint32_t ref_object_number;
56 uint32_t referenced_object_number;
59 std::vector<ReferenceEntry> GetReferenceEntries() {
60 std::vector<ReferenceEntry> reference_entries;
61 while (!object_queue_.empty()) {
65 switch (current_object->GetType()) {
68 for (
const auto& it : locker) {
69 PushNewObject(current_object, it);
75 for (
const auto& it : locker) {
76 PushNewObject(current_object, it.second);
81 const CPDF_Reference* ref_object = current_object->AsReference();
82 const uint32_t ref_object_number = GetObjectNumber(ref_object);
92 document_->GetIndirectObject(referenced_object_number);
95 if (referenced_object) {
96 CHECK(referenced_object_number);
97 reference_entries.push_back(
98 {ref_object_number, referenced_object_number});
99 PushNewObject(ref_object, referenced_object);
105 current_object->AsStream()->GetDict();
106 CHECK(dict->IsInline());
108 for (
const auto& it : locker) {
109 PushNewObject(current_object, it.second);
118 return reference_entries;
121 void CalculateReferenceCounts(
122 const std::vector<ReferenceEntry>& reference_entries) {
125 std::set<uint32_t> seen_ref_objects;
127 for (
const ReferenceEntry& entry : reference_entries) {
129 if (entry.referenced_object_number == entry.ref_object_number) {
134 if (pdfium::Contains(seen_ref_objects, entry.ref_object_number) &&
135 pdfium::Contains(seen_ref_objects, entry.referenced_object_number)) {
139 ++referenced_objects_[entry.referenced_object_number];
140 if (entry.ref_object_number) {
141 seen_ref_objects.insert(entry.ref_object_number);
146 void PushNewObject(
const CPDF_Object* parent_object,
148 CHECK(parent_object);
150 const bool inserted = seen_objects_.insert(child_object).second;
154 const uint32_t child_object_number = child_object->GetObjNum();
155 if (child_object_number) {
156 object_number_map_[child_object] = child_object_number;
159 auto it = object_number_map_.find(parent_object);
160 if (it != object_number_map_.end()) {
161 object_number_map_[child_object] = it->second;
164 object_queue_.push(std::move(child_object));
168 uint32_t GetObjectNumber(
const CPDF_Object* object)
const {
169 auto it = object_number_map_.find(object);
170 return it != object_number_map_.end() ? it->second : 0;
178 std::queue<RetainPtr<
const CPDF_Object>> object_queue_;
185 std::map<
const CPDF_Object*, uint32_t> object_number_map_;
189 std::set<
const CPDF_Object*> seen_objects_;
194 std::map<uint32_t,
int> referenced_objects_;
200 ObjectTreeTraverser traverser(document);
201 traverser.Traverse();
203 std::set<uint32_t> results;
204 for (
const auto& it : traverser.referenced_objects()) {
205 results.insert(it.first);
212 ObjectTreeTraverser traverser(document);
213 traverser.Traverse();
215 std::set<uint32_t> results;
216 for (
const auto& it : traverser.referenced_objects()) {
218 results.insert(it.first);
RetainPtr< const CPDF_Object > GetDirect() const
uint32_t GetObjNum() const
const CPDF_Dictionary * GetTrailer() const
uint32_t GetTrailerObjectNumber() const
bool HasIndirectObjectHolder() const
uint32_t GetRefObjNum() const
std::set< uint32_t > GetObjectsWithReferences(const CPDF_Document *document)
std::set< uint32_t > GetObjectsWithMultipleReferences(const CPDF_Document *document)