diff options
author | Matthew Olsson <matthewcolsson@gmail.com> | 2021-04-30 18:23:17 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-10 10:32:39 +0200 |
commit | a8f5b6aaa3405e4b4eda49888ee9da8572d5473d (patch) | |
tree | e5c95bb185071cda2f81d5802cd67b366533eb2f /Userland/Libraries/LibPDF/Object.cpp | |
parent | af9a7b13748cc4ccffe6f257c520b2a3b040102b (diff) | |
download | serenity-a8f5b6aaa3405e4b4eda49888ee9da8572d5473d.zip |
LibPDF: Create basic object structure
This commit is the start of LibPDF, and introduces some basic structure
objects. This emulates LibJS's Value structure, where Value is a simple
class that can contain a pointer to a more complex Object class with
more data. All of the basic PDF objects have a representation.
Diffstat (limited to 'Userland/Libraries/LibPDF/Object.cpp')
-rw-r--r-- | Userland/Libraries/LibPDF/Object.cpp | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/Userland/Libraries/LibPDF/Object.cpp b/Userland/Libraries/LibPDF/Object.cpp new file mode 100644 index 0000000000..4fca01a497 --- /dev/null +++ b/Userland/Libraries/LibPDF/Object.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021, Matthew Olsson <mattco@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Hex.h> +#include <LibPDF/Object.h> + +namespace PDF { + +static void append_indent(StringBuilder& builder, int indent) +{ + for (int i = 0; i < indent; i++) + builder.append(" "); +} + +String StringObject::to_string(int) const +{ + if (is_binary()) + return String::formatted("<{}>", encode_hex(string().bytes()).to_uppercase()); + return String::formatted("({})", string()); +} + +String NameObject::to_string(int) const +{ + StringBuilder builder; + builder.appendff("/{}", this->name()); + return builder.to_string(); +} + +String ArrayObject::to_string(int indent) const +{ + StringBuilder builder; + builder.append("[\n"); + bool first = true; + + for (auto& element : elements()) { + if (!first) + builder.append(",\n"); + first = false; + append_indent(builder, indent + 1); + builder.appendff("{}", element.to_string(indent)); + } + + builder.append('\n'); + append_indent(builder, indent); + builder.append(']'); + return builder.to_string(); +} + +String DictObject::to_string(int indent) const +{ + StringBuilder builder; + builder.append("<<\n"); + bool first = true; + + for (auto& [key, value] : map()) { + if (!first) + builder.append(",\n"); + first = false; + append_indent(builder, indent + 1); + builder.appendff("/{} ", key); + builder.appendff("{}", value.to_string(indent + 1)); + } + + builder.append('\n'); + append_indent(builder, indent); + builder.append(">>"); + return builder.to_string(); +} + +String StreamObject::to_string(int indent) const +{ + StringBuilder builder; + builder.append("stream\n"); + append_indent(builder, indent); + builder.appendff("{}\n", dict()->to_string(indent + 1)); + append_indent(builder, indent + 1); + + auto string = encode_hex(bytes()); + while (true) { + if (string.length() > 60) { + builder.appendff("{}\n", string.substring(0, 60)); + append_indent(builder, indent); + string = string.substring(60); + continue; + } + + builder.appendff("{}\n", string); + break; + } + + append_indent(builder, indent); + builder.append("endstream"); + return builder.to_string(); +} + +String IndirectValue::to_string(int indent) const +{ + StringBuilder builder; + builder.appendff("{} {} obj\n", index(), generation_index()); + append_indent(builder, indent + 1); + builder.append(value().to_string(indent + 1)); + builder.append('\n'); + append_indent(builder, indent); + builder.append("endobj"); + return builder.to_string(); +} + +String IndirectValueRef::to_string(int) const +{ + return String::formatted("{} {} R", index(), generation_index()); +} + +} |