blob: 59076009acb2604f7eba53c2a8787cdb062e0e3d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
/*
* Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Format.h>
#include <AK/RefCounted.h>
#include <AK/String.h>
#include <AK/Vector.h>
namespace PDF {
constexpr long invalid_byte_offset = NumericLimits<long>::max();
struct XRefEntry {
long byte_offset { invalid_byte_offset };
u16 generation_number { 0 };
bool in_use { false };
};
struct XRefSection {
int starting_index;
int count;
Vector<XRefEntry> entries;
};
class XRefTable final : public RefCounted<XRefTable> {
public:
PDFErrorOr<void> merge(XRefTable&& other)
{
auto this_size = m_entries.size();
auto other_size = other.m_entries.size();
m_entries.ensure_capacity(other_size);
for (size_t i = 0; i < other_size; i++) {
auto other_entry = other.m_entries[i];
if (i >= this_size) {
m_entries.unchecked_append(other_entry);
continue;
}
auto this_entry = m_entries[i];
if (this_entry.byte_offset == invalid_byte_offset) {
m_entries[i] = other_entry;
} else if (other_entry.byte_offset != invalid_byte_offset) {
// Both xref tables have an entry for the same object index
return Error { Error::Type::Parse, "Conflicting xref entry during merge" };
}
}
return {};
}
void add_section(XRefSection const& section)
{
m_entries.ensure_capacity(section.starting_index + section.count);
for (int i = static_cast<int>(m_entries.size()); i < section.starting_index; i++)
m_entries.append(XRefEntry {});
for (auto& entry : section.entries)
m_entries.append(entry);
}
[[nodiscard]] ALWAYS_INLINE bool has_object(size_t index) const
{
return index < m_entries.size() && m_entries[index].byte_offset != -1;
}
[[nodiscard]] ALWAYS_INLINE long byte_offset_for_object(size_t index) const
{
VERIFY(has_object(index));
return m_entries[index].byte_offset;
}
[[nodiscard]] ALWAYS_INLINE u16 generation_number_for_object(size_t index) const
{
VERIFY(has_object(index));
return m_entries[index].generation_number;
}
[[nodiscard]] ALWAYS_INLINE bool is_object_in_use(size_t index) const
{
VERIFY(has_object(index));
return m_entries[index].in_use;
}
private:
friend struct AK::Formatter<PDF::XRefTable>;
Vector<XRefEntry> m_entries;
};
}
namespace AK {
template<>
struct Formatter<PDF::XRefEntry> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& builder, PDF::XRefEntry const& entry)
{
return Formatter<StringView>::format(builder,
String::formatted("XRefEntry {{ offset={} generation={} used={} }}",
entry.byte_offset,
entry.generation_number,
entry.in_use));
}
};
template<>
struct Formatter<PDF::XRefTable> : Formatter<StringView> {
ErrorOr<void> format(FormatBuilder& format_builder, PDF::XRefTable const& table)
{
StringBuilder builder;
builder.append("XRefTable {");
for (auto& entry : table.m_entries)
builder.appendff("\n {}", entry);
builder.append("\n}");
return Formatter<StringView>::format(format_builder, builder.to_string());
}
};
}
|