From a8f5b6aaa3405e4b4eda49888ee9da8572d5473d Mon Sep 17 00:00:00 2001 From: Matthew Olsson Date: Fri, 30 Apr 2021 18:23:17 -0700 Subject: 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. --- Userland/Libraries/LibPDF/Object.cpp | 116 +++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Userland/Libraries/LibPDF/Object.cpp (limited to 'Userland/Libraries/LibPDF/Object.cpp') 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 + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +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()); +} + +} -- cgit v1.2.3