123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /*
- * Copyright (c) 2022, Julian Offenhäuser <offenhaeuser@protonmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <LibGfx/Font/PathRasterizer.h>
- #include <LibPDF/CommonNames.h>
- #include <LibPDF/Encoding.h>
- #include <LibPDF/Fonts/PS1FontProgram.h>
- #include <LibPDF/Reader.h>
- #include <ctype.h>
- #include <math.h>
- namespace PDF {
- PDFErrorOr<NonnullRefPtr<Type1FontProgram>> PS1FontProgram::create(ReadonlyBytes const& bytes, RefPtr<Encoding> encoding, size_t cleartext_length, size_t encrypted_length)
- {
- Reader reader(bytes);
- if (reader.remaining() == 0)
- return error("Empty font program");
- reader.move_to(0);
- if (reader.remaining() < 2 || !reader.matches("%!"))
- return error("Not a font program");
- if (!seek_name(reader, CommonNames::Encoding))
- return error("Missing encoding array");
- auto font_program = adopt_ref(*new PS1FontProgram());
- if (encoding) {
- // 9.6.6.2 Encodings for Type 1 Fonts:
- // An Encoding entry may override a Type 1 font’s mapping from character codes to character names.
- font_program->set_encoding(move(encoding));
- } else {
- if (TRY(parse_word(reader)) == "StandardEncoding") {
- font_program->set_encoding(Encoding::standard_encoding());
- } else {
- auto encoding = Encoding::create();
- while (reader.remaining()) {
- auto word = TRY(parse_word(reader));
- if (word == "readonly") {
- break;
- } else if (word == "dup") {
- u8 char_code = TRY(parse_int(reader));
- auto name = TRY(parse_word(reader));
- encoding->set(char_code, name.starts_with('/') ? name.substring_view(1) : name.view());
- }
- }
- font_program->set_encoding(move(encoding));
- }
- }
- bool found_font_matrix = seek_name(reader, "FontMatrix");
- if (found_font_matrix) {
- auto array = TRY(parse_number_array(reader, 6));
- font_program->set_font_matrix({ array[0], array[1], array[2], array[3], array[4], array[5] });
- } else {
- font_program->set_font_matrix({ 0.001f, 0.0f, 0.0f, 0.001f, 0.0f, 0.0f });
- }
- auto decrypted = TRY(decrypt(reader.bytes().slice(cleartext_length, encrypted_length), 55665, 4));
- TRY(font_program->parse_encrypted_portion(decrypted));
- return font_program;
- }
- PDFErrorOr<void> PS1FontProgram::parse_encrypted_portion(ByteBuffer const& buffer)
- {
- Reader reader(buffer);
- if (seek_name(reader, "lenIV"))
- m_lenIV = TRY(parse_int(reader));
- if (!seek_name(reader, "Subrs"))
- return error("Missing subroutine array");
- auto subroutines = TRY(parse_subroutines(reader));
- if (!seek_name(reader, "CharStrings"))
- return error("Missing char strings array");
- while (reader.remaining()) {
- auto word = TRY(parse_word(reader));
- VERIFY(!word.is_empty());
- if (word == "end")
- break;
- if (word[0] == '/') {
- auto encrypted_size = TRY(parse_int(reader));
- auto rd = TRY(parse_word(reader));
- if (rd == "-|" || rd == "RD") {
- auto line = TRY(decrypt(reader.bytes().slice(reader.offset(), encrypted_size), m_encryption_key, m_lenIV));
- reader.move_by(encrypted_size);
- auto glyph_name = word.substring_view(1);
- GlyphParserState state;
- TRY(add_glyph(glyph_name, TRY(parse_glyph(line, subroutines, state, false))));
- }
- }
- }
- consolidate_glyphs();
- return {};
- }
- PDFErrorOr<Vector<ByteBuffer>> PS1FontProgram::parse_subroutines(Reader& reader) const
- {
- if (!reader.matches_number())
- return error("Expected array length");
- auto length = TRY(parse_int(reader));
- VERIFY(length <= 1024);
- Vector<ByteBuffer> array;
- TRY(array.try_resize(length));
- while (reader.remaining()) {
- auto word = TRY(parse_word(reader));
- if (word.is_empty())
- VERIFY(0);
- if (word == "dup") {
- auto index = TRY(parse_int(reader));
- auto entry = TRY(parse_word(reader));
- if (entry.is_empty())
- return error("Empty array entry");
- if (index >= length)
- return error("Array index out of bounds");
- if (isdigit(entry[0])) {
- auto maybe_encrypted_size = entry.to_int();
- if (!maybe_encrypted_size.has_value())
- return error("Malformed array");
- auto rd = TRY(parse_word(reader));
- if (rd == "-|" || rd == "RD") {
- array[index] = TRY(decrypt(reader.bytes().slice(reader.offset(), maybe_encrypted_size.value()), m_encryption_key, m_lenIV));
- reader.move_by(maybe_encrypted_size.value());
- }
- } else {
- array[index] = TRY(ByteBuffer::copy(entry.bytes()));
- }
- } else if (word == "index" || word == "def" || word == "ND") {
- break;
- }
- }
- return array;
- }
- PDFErrorOr<Vector<float>> PS1FontProgram::parse_number_array(Reader& reader, size_t length)
- {
- Vector<float> array;
- TRY(array.try_resize(length));
- reader.consume_whitespace();
- if (!reader.consume('['))
- return error("Expected array to start with '['");
- reader.consume_whitespace();
- for (size_t i = 0; i < length; ++i)
- array.at(i) = TRY(parse_float(reader));
- if (!reader.consume(']'))
- return error("Expected array to end with ']'");
- return array;
- }
- PDFErrorOr<DeprecatedString> PS1FontProgram::parse_word(Reader& reader)
- {
- reader.consume_whitespace();
- auto start = reader.offset();
- reader.move_while([&](char c) {
- return !reader.matches_whitespace() && c != '[' && c != ']';
- });
- auto end = reader.offset();
- if (reader.matches_whitespace())
- reader.consume();
- return StringView(reader.bytes().data() + start, end - start);
- }
- PDFErrorOr<float> PS1FontProgram::parse_float(Reader& reader)
- {
- auto word = TRY(parse_word(reader));
- return strtof(DeprecatedString(word).characters(), nullptr);
- }
- PDFErrorOr<int> PS1FontProgram::parse_int(Reader& reader)
- {
- auto maybe_int = TRY(parse_word(reader)).to_int();
- if (!maybe_int.has_value())
- return error("Invalid int");
- return maybe_int.value();
- }
- PDFErrorOr<ByteBuffer> PS1FontProgram::decrypt(ReadonlyBytes const& encrypted, u16 key, size_t skip)
- {
- auto decrypted = TRY(ByteBuffer::create_uninitialized(encrypted.size() - skip));
- u16 R = key;
- u16 c1 = 52845;
- u16 c2 = 22719;
- for (size_t i = 0; i < encrypted.size(); ++i) {
- u8 C = encrypted[i];
- u8 P = C ^ (R >> 8);
- R = (C + R) * c1 + c2;
- if (i >= skip)
- decrypted[i - skip] = P;
- }
- return decrypted;
- }
- bool PS1FontProgram::seek_name(Reader& reader, DeprecatedString const& name)
- {
- auto start = reader.offset();
- reader.move_to(0);
- while (reader.remaining()) {
- if (reader.consume('/') && reader.matches(name.characters())) {
- // Skip name
- reader.move_while([&](char) {
- return reader.matches_regular_character();
- });
- reader.consume_whitespace();
- return true;
- }
- }
- // Jump back to where we started
- reader.move_to(start);
- return false;
- }
- }
|