diff --git a/Userland/Libraries/LibPDF/Document.cpp b/Userland/Libraries/LibPDF/Document.cpp index dfd0e0e786..e7a45a8519 100644 --- a/Userland/Libraries/LibPDF/Document.cpp +++ b/Userland/Libraries/LibPDF/Document.cpp @@ -101,20 +101,18 @@ Page Document::get_page(u32 index) Value Document::resolve(const Value& value) { + if (value.is_ref()) { + // FIXME: Surely indirect PDF objects can't contain another indirect PDF object, + // right? Unsure from the spec, but if they can, these return values would have + // to be wrapped with another resolve() call. + return get_or_load_value(value.as_ref_index()); + } + if (!value.is_object()) return value; auto obj = value.as_object(); - // FIXME: Surely indirect PDF objects can't contain another indirect PDF object, - // right? Unsure from the spec, but if they can, these return values would have - // to be wrapped with another resolve() call. - - if (obj->is_indirect_value_ref()) { - auto object_index = static_cast>(obj)->index(); - return get_or_load_value(object_index); - } - if (obj->is_indirect_value()) return static_cast>(obj)->value(); @@ -137,13 +135,13 @@ void Document::add_page_tree_node_to_page_tree(NonnullRefPtr page_tr // these pages to the overall page tree for (auto& value : *kids_array) { - auto reference = object_cast(value.as_object()); - auto byte_offset = m_xref_table.byte_offset_for_object(reference->index()); + auto reference_index = value.as_ref_index(); + auto byte_offset = m_xref_table.byte_offset_for_object(reference_index); auto maybe_page_tree_node = m_parser.conditionally_parse_page_tree_node_at_offset(byte_offset); if (maybe_page_tree_node) { add_page_tree_node_to_page_tree(maybe_page_tree_node.release_nonnull()); } else { - m_page_object_indices.append(reference->index()); + m_page_object_indices.append(reference_index); } } @@ -151,10 +149,8 @@ void Document::add_page_tree_node_to_page_tree(NonnullRefPtr page_tr } // We know all of the kids are leaf nodes - for (auto& value : *kids_array) { - auto reference = object_cast(value.as_object()); - m_page_object_indices.append(reference->index()); - } + for (auto& value : *kids_array) + m_page_object_indices.append(value.as_ref_index()); } } diff --git a/Userland/Libraries/LibPDF/Forward.h b/Userland/Libraries/LibPDF/Forward.h index 05ef8249f2..76982f2ae9 100644 --- a/Userland/Libraries/LibPDF/Forward.h +++ b/Userland/Libraries/LibPDF/Forward.h @@ -14,18 +14,14 @@ class Object; // Note: This macro doesn't care about PlainTextStreamObject and EncodedStreamObject because // we never need to work directly with either of them. -#define ENUMERATE_DIRECT_OBJECT_TYPES(V) \ - V(StringObject, string) \ - V(NameObject, name) \ - V(ArrayObject, array) \ - V(DictObject, dict) \ - V(StreamObject, stream) \ +#define ENUMERATE_OBJECT_TYPES(V) \ + V(StringObject, string) \ + V(NameObject, name) \ + V(ArrayObject, array) \ + V(DictObject, dict) \ + V(StreamObject, stream) \ V(IndirectValue, indirect_value) -#define ENUMERATE_OBJECT_TYPES(V) \ - ENUMERATE_DIRECT_OBJECT_TYPES(V) \ - V(IndirectValueRef, indirect_value_ref) - #define FORWARD_DECL(class_name, _) class class_name; ENUMERATE_OBJECT_TYPES(FORWARD_DECL) #undef FORWARD_DECL diff --git a/Userland/Libraries/LibPDF/Object.cpp b/Userland/Libraries/LibPDF/Object.cpp index 3cd861cb61..1b7921a092 100644 --- a/Userland/Libraries/LibPDF/Object.cpp +++ b/Userland/Libraries/LibPDF/Object.cpp @@ -30,7 +30,7 @@ NonnullRefPtr DictObject::get_object(Document* document, const FlyString { \ return document->resolve_to(get(key).value()); \ } -ENUMERATE_DIRECT_OBJECT_TYPES(DEFINE_ACCESSORS) +ENUMERATE_OBJECT_TYPES(DEFINE_ACCESSORS) #undef DEFINE_INDEXER static void append_indent(StringBuilder& builder, int indent) @@ -132,9 +132,4 @@ String IndirectValue::to_string(int indent) const return builder.to_string(); } -String IndirectValueRef::to_string(int) const -{ - return String::formatted("{} {} R", index(), generation_index()); -} - } diff --git a/Userland/Libraries/LibPDF/Object.h b/Userland/Libraries/LibPDF/Object.h index 84a7bfb2a0..e75d38c0a3 100644 --- a/Userland/Libraries/LibPDF/Object.h +++ b/Userland/Libraries/LibPDF/Object.h @@ -222,26 +222,6 @@ private: Value m_value; }; -class IndirectValueRef final : public Object { -public: - IndirectValueRef(u32 index, u32 generation_index) - : m_index(index) - { - set_generation_index(generation_index); - } - - ~IndirectValueRef() override = default; - - [[nodiscard]] ALWAYS_INLINE u32 index() const { return m_index; } - - ALWAYS_INLINE bool is_indirect_value_ref() const override { return true; } - ALWAYS_INLINE const char* type_name() const override { return "indirect_object_ref"; } - String to_string(int indent) const override; - -private: - u32 m_index; -}; - template [[nodiscard]] ALWAYS_INLINE static NonnullRefPtr object_cast(NonnullRefPtr obj #ifdef PDF_DEBUG diff --git a/Userland/Libraries/LibPDF/Parser.cpp b/Userland/Libraries/LibPDF/Parser.cpp index 07e57046fe..f78f5211c0 100644 --- a/Userland/Libraries/LibPDF/Parser.cpp +++ b/Userland/Libraries/LibPDF/Parser.cpp @@ -321,7 +321,7 @@ Value Parser::parse_possible_indirect_value_or_ref() m_reader.discard(); consume(); consume_whitespace(); - return make_object(first_number.as_int(), second_number.as_int()); + return Value(first_number.as_int(), second_number.as_int()); } if (m_reader.matches("obj")) { diff --git a/Userland/Libraries/LibPDF/Value.cpp b/Userland/Libraries/LibPDF/Value.cpp index 8d79bb9743..a254d78ea0 100644 --- a/Userland/Libraries/LibPDF/Value.cpp +++ b/Userland/Libraries/LibPDF/Value.cpp @@ -30,6 +30,9 @@ Value& Value::operator=(const Value& other) case Type::Float: m_as_float = other.m_as_float; break; + case Type::Ref: + m_as_ref = other.m_as_ref; + break; case Type::Object: m_as_object = other.m_as_object; if (m_as_object) @@ -50,6 +53,8 @@ String Value::to_string(int indent) const return String::number(as_int()); case Type::Float: return String::number(as_float()); + case Type::Ref: + return String::formatted("{} {} R", as_ref_index(), as_ref_generation_index()); case Type::Object: return as_object()->to_string(indent); } diff --git a/Userland/Libraries/LibPDF/Value.h b/Userland/Libraries/LibPDF/Value.h index 6999902bfc..cb75a92662 100644 --- a/Userland/Libraries/LibPDF/Value.h +++ b/Userland/Libraries/LibPDF/Value.h @@ -14,6 +14,14 @@ class Object; class Value { public: + // We store refs as u32, with 18 bits for the index and 14 bits for the + // generation index. The generation index is stored in the higher bits. + // This may need to be rethought later, as the max generation index is + // 2^16 and the max for the object index is probably 2^32 (I don't know + // exactly) + static constexpr auto max_ref_index = (1 << 19) - 1; // 2 ^ 18 - 1 + static constexpr auto max_ref_generation_index = (1 << 15) - 1; // 2 ^ 14 - 1 + Value() : m_type(Type::Null) { @@ -37,6 +45,14 @@ public: m_as_float = f; } + Value(u32 index, u32 generation_index) + : m_type(Type::Ref) + { + VERIFY(index < max_ref_index); + VERIFY(generation_index < max_ref_generation_index); + m_as_ref = (generation_index << 14) | index; + } + template Value(NonnullRefPtr obj) : m_type(Type::Object) @@ -59,7 +75,7 @@ public: [[nodiscard]] ALWAYS_INLINE bool is_int() const { return m_type == Type::Int; } [[nodiscard]] ALWAYS_INLINE bool is_float() const { return m_type == Type::Float; } [[nodiscard]] ALWAYS_INLINE bool is_number() const { return is_int() || is_float(); } - + [[nodiscard]] ALWAYS_INLINE bool is_ref() const { return m_type == Type::Ref; } [[nodiscard]] ALWAYS_INLINE bool is_object() const { return m_type == Type::Object; } [[nodiscard]] ALWAYS_INLINE bool as_bool() const @@ -94,6 +110,18 @@ public: return static_cast(as_int()); } + [[nodiscard]] ALWAYS_INLINE u32 as_ref_index() const + { + VERIFY(is_ref()); + return m_as_ref & 0x3ffff; + } + + [[nodiscard]] ALWAYS_INLINE u32 as_ref_generation_index() const + { + VERIFY(is_ref()); + return m_as_ref >> 18; + } + [[nodiscard]] ALWAYS_INLINE NonnullRefPtr as_object() const { return *m_as_object; } [[nodiscard]] ALWAYS_INLINE explicit operator bool() const { return !is_null(); } @@ -106,12 +134,14 @@ private: Bool, Int, Float, + Ref, Object, }; union { bool m_as_bool; int m_as_int; + u32 m_as_ref; float m_as_float; Object* m_as_object; };