ObjectDerivatives.cpp 7.5 KB

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