Serenity Operating System
1/*
2 * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Hex.h>
8#include <LibPDF/Document.h>
9#include <LibPDF/ObjectDerivatives.h>
10
11namespace PDF {
12
13PDFErrorOr<NonnullRefPtr<Object>> ArrayObject::get_object_at(Document* document, size_t index) const
14{
15 return document->resolve_to<Object>(at(index));
16}
17
18PDFErrorOr<NonnullRefPtr<Object>> DictObject::get_object(Document* document, DeprecatedFlyString const& key) const
19{
20 return document->resolve_to<Object>(get_value(key));
21}
22
23#define DEFINE_ACCESSORS(class_name, snake_name) \
24 PDFErrorOr<NonnullRefPtr<class_name>> ArrayObject::get_##snake_name##_at(Document* document, size_t index) const \
25 { \
26 if (index >= m_elements.size()) \
27 return Error { Error::Type::Internal, "Out of bounds array access" }; \
28 return document->resolve_to<class_name>(m_elements[index]); \
29 } \
30 \
31 NonnullRefPtr<class_name> ArrayObject::get_##snake_name##_at(size_t index) const \
32 { \
33 VERIFY(index < m_elements.size()); \
34 return cast_to<class_name>(m_elements[index]); \
35 } \
36 \
37 PDFErrorOr<NonnullRefPtr<class_name>> DictObject::get_##snake_name(Document* document, DeprecatedFlyString const& key) const \
38 { \
39 return document->resolve_to<class_name>(get_value(key)); \
40 } \
41 \
42 NonnullRefPtr<class_name> DictObject::get_##snake_name(DeprecatedFlyString const& key) const \
43 { \
44 return cast_to<class_name>(get_value(key)); \
45 }
46
47ENUMERATE_OBJECT_TYPES(DEFINE_ACCESSORS)
48#undef DEFINE_INDEXER
49
50static void append_indent(StringBuilder& builder, int indent)
51{
52 for (int i = 0; i < indent; i++)
53 builder.append(" "sv);
54}
55
56DeprecatedString StringObject::to_deprecated_string(int) const
57{
58 if (is_binary())
59 return DeprecatedString::formatted("<{}>", encode_hex(string().bytes()).to_uppercase());
60 return DeprecatedString::formatted("({})", string());
61}
62
63DeprecatedString NameObject::to_deprecated_string(int) const
64{
65 StringBuilder builder;
66 builder.appendff("/{}", this->name());
67 return builder.to_deprecated_string();
68}
69
70Vector<float> ArrayObject::float_elements() const
71{
72 Vector<float> values;
73 values.ensure_capacity(m_elements.size());
74 for (auto const& value : m_elements) {
75 values.append(value.to_float());
76 }
77 return values;
78}
79
80DeprecatedString ArrayObject::to_deprecated_string(int indent) const
81{
82 StringBuilder builder;
83 builder.append("[\n"sv);
84 bool first = true;
85
86 for (auto& element : elements()) {
87 if (!first)
88 builder.append(",\n"sv);
89 first = false;
90 append_indent(builder, indent + 1);
91 builder.appendff("{}", element.to_deprecated_string(indent));
92 }
93
94 builder.append('\n');
95 append_indent(builder, indent);
96 builder.append(']');
97 return builder.to_deprecated_string();
98}
99
100DeprecatedString DictObject::to_deprecated_string(int indent) const
101{
102 StringBuilder builder;
103 builder.append("<<\n"sv);
104 bool first = true;
105
106 for (auto& [key, value] : map()) {
107 if (!first)
108 builder.append(",\n"sv);
109 first = false;
110 append_indent(builder, indent + 1);
111 builder.appendff("/{} ", key);
112 builder.appendff("{}", value.to_deprecated_string(indent + 1));
113 }
114
115 builder.append('\n');
116 append_indent(builder, indent);
117 builder.append(">>"sv);
118 return builder.to_deprecated_string();
119}
120
121DeprecatedString StreamObject::to_deprecated_string(int indent) const
122{
123 StringBuilder builder;
124 builder.append("stream\n"sv);
125 append_indent(builder, indent);
126 builder.appendff("{}\n", dict()->to_deprecated_string(indent + 1));
127 append_indent(builder, indent + 1);
128
129 auto string = encode_hex(bytes());
130 while (true) {
131 if (string.length() > 60) {
132 builder.appendff("{}\n", string.substring(0, 60));
133 append_indent(builder, indent);
134 string = string.substring(60);
135 continue;
136 }
137
138 builder.appendff("{}\n", string);
139 break;
140 }
141
142 append_indent(builder, indent);
143 builder.append("endstream"sv);
144 return builder.to_deprecated_string();
145}
146
147DeprecatedString IndirectValue::to_deprecated_string(int indent) const
148{
149 StringBuilder builder;
150 builder.appendff("{} {} obj\n", index(), generation_index());
151 append_indent(builder, indent + 1);
152 builder.append(value().to_deprecated_string(indent + 1));
153 builder.append('\n');
154 append_indent(builder, indent);
155 builder.append("endobj"sv);
156 return builder.to_deprecated_string();
157}
158
159}