TestPDF.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright (c) 2021, Simon Woertz <simon@woertz.at>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/DeprecatedString.h>
  7. #include <AK/Forward.h>
  8. #include <LibCore/MappedFile.h>
  9. #include <LibPDF/CommonNames.h>
  10. #include <LibPDF/Document.h>
  11. #include <LibPDF/Function.h>
  12. #include <LibTest/Macros.h>
  13. #include <LibTest/TestCase.h>
  14. TEST_CASE(linearized_pdf)
  15. {
  16. auto file = MUST(Core::MappedFile::map("linearized.pdf"sv));
  17. auto document = MUST(PDF::Document::create(file->bytes()));
  18. MUST(document->initialize());
  19. EXPECT_EQ(document->get_page_count(), 1U);
  20. }
  21. TEST_CASE(non_linearized_pdf)
  22. {
  23. auto file = MUST(Core::MappedFile::map("non-linearized.pdf"sv));
  24. auto document = MUST(PDF::Document::create(file->bytes()));
  25. MUST(document->initialize());
  26. EXPECT_EQ(document->get_page_count(), 1U);
  27. }
  28. TEST_CASE(complex_pdf)
  29. {
  30. auto file = MUST(Core::MappedFile::map("complex.pdf"sv));
  31. auto document = MUST(PDF::Document::create(file->bytes()));
  32. MUST(document->initialize());
  33. EXPECT_EQ(document->get_page_count(), 3U);
  34. }
  35. TEST_CASE(empty_file_issue_10702)
  36. {
  37. AK::ReadonlyBytes empty;
  38. auto document = PDF::Document::create(empty);
  39. EXPECT(document.is_error());
  40. }
  41. TEST_CASE(truncated_pdf_header_issue_10717)
  42. {
  43. AK::DeprecatedString string { "%PDF-2.11%" };
  44. auto document = PDF::Document::create(string.bytes());
  45. EXPECT(document.is_error());
  46. }
  47. TEST_CASE(encrypted_with_aes)
  48. {
  49. auto file = MUST(Core::MappedFile::map("password-is-sup.pdf"sv));
  50. auto document = MUST(PDF::Document::create(file->bytes()));
  51. EXPECT(document->security_handler()->try_provide_user_password("sup"sv));
  52. MUST(document->initialize());
  53. EXPECT_EQ(document->get_page_count(), 1U);
  54. auto info_dict = MUST(document->info_dict()).value();
  55. EXPECT_EQ(MUST(info_dict.title()).value(), "sup");
  56. EXPECT_EQ(MUST(info_dict.creator()).value(), "TextEdit");
  57. }
  58. TEST_CASE(encrypted_object_stream)
  59. {
  60. auto file = MUST(Core::MappedFile::map("encryption_nocopy.pdf"sv));
  61. auto document = MUST(PDF::Document::create(file->bytes()));
  62. MUST(document->initialize());
  63. EXPECT_EQ(document->get_page_count(), 1U);
  64. auto info_dict = MUST(document->info_dict()).value();
  65. EXPECT_EQ(MUST(info_dict.author()).value(), "van der Knijff");
  66. EXPECT_EQ(MUST(info_dict.creator()).value(), "Acrobat PDFMaker 9.1 voor Word");
  67. }
  68. TEST_CASE(malformed_pdf_document)
  69. {
  70. Array test_inputs = {
  71. "oss-fuzz-testcase-62065.pdf"sv
  72. };
  73. for (auto test_input : test_inputs) {
  74. auto file = MUST(Core::MappedFile::map(test_input));
  75. auto document_or_error = PDF::Document::create(file->bytes());
  76. EXPECT(document_or_error.is_error());
  77. }
  78. }
  79. static PDF::Value make_array(Vector<float> floats)
  80. {
  81. Vector<PDF::Value> values;
  82. for (auto f : floats)
  83. values.append(PDF::Value { f });
  84. return PDF::Value { adopt_ref(*new PDF::ArrayObject(move(values))) };
  85. }
  86. static PDF::PDFErrorOr<NonnullRefPtr<PDF::Function>> make_function(int type, ReadonlyBytes data, Vector<float> domain, Vector<float> range, Function<void(HashMap<DeprecatedFlyString, PDF::Value>&)> extra_keys = nullptr)
  87. {
  88. HashMap<DeprecatedFlyString, PDF::Value> map;
  89. map.set(PDF::CommonNames::FunctionType, PDF::Value { type });
  90. map.set(PDF::CommonNames::Domain, make_array(move(domain)));
  91. map.set(PDF::CommonNames::Range, make_array(move(range)));
  92. if (extra_keys)
  93. extra_keys(map);
  94. auto dict = adopt_ref(*new PDF::DictObject(move(map)));
  95. auto stream = adopt_ref(*new PDF::StreamObject(dict, MUST(ByteBuffer::copy(data))));
  96. // document isn't used for anything, but UBSan complains about a (harmless) method call on a null object without it.
  97. auto file = MUST(Core::MappedFile::map("linearized.pdf"sv));
  98. auto document = MUST(PDF::Document::create(file->bytes()));
  99. return PDF::Function::create(document, stream);
  100. }
  101. static PDF::PDFErrorOr<NonnullRefPtr<PDF::Function>> make_sampled_function(ReadonlyBytes data, Vector<float> domain, Vector<float> range, Vector<float> sizes)
  102. {
  103. return make_function(0, data, move(domain), move(range), [&sizes](auto& map) {
  104. map.set(PDF::CommonNames::Size, make_array(sizes));
  105. map.set(PDF::CommonNames::BitsPerSample, PDF::Value { 8 });
  106. });
  107. }
  108. TEST_CASE(sampled)
  109. {
  110. auto f1 = MUST(make_sampled_function(Vector<u8> { { 0, 255, 0 } }, { 0.0f, 1.0f }, { 0.0f, 10.0f }, { 3 }));
  111. EXPECT_EQ(MUST(f1->evaluate(Vector<float> { 0.0f })), Vector<float> { 0.0f });
  112. EXPECT_EQ(MUST(f1->evaluate(Vector<float> { 0.25f })), Vector<float> { 5.0f });
  113. EXPECT_EQ(MUST(f1->evaluate(Vector<float> { 0.5f })), Vector<float> { 10.0f });
  114. EXPECT_EQ(MUST(f1->evaluate(Vector<float> { 0.75f })), Vector<float> { 5.0f });
  115. EXPECT_EQ(MUST(f1->evaluate(Vector<float> { 1.0f })), Vector<float> { 0.0f });
  116. auto f2 = MUST(make_sampled_function(Vector<u8> { { 0, 255, 0, 255, 0, 255 } }, { 0.0f, 1.0f }, { 0.0f, 10.0f, 0.0f, 8.0f }, { 3 }));
  117. EXPECT_EQ(MUST(f2->evaluate(Vector<float> { 0.0f })), (Vector<float> { 0.0f, 8.0f }));
  118. EXPECT_EQ(MUST(f2->evaluate(Vector<float> { 0.25f })), (Vector<float> { 5.0f, 4.0f }));
  119. EXPECT_EQ(MUST(f2->evaluate(Vector<float> { 0.5f })), (Vector<float> { 10.0f, 0.0f }));
  120. EXPECT_EQ(MUST(f2->evaluate(Vector<float> { 0.75f })), (Vector<float> { 5.0f, 4.0f }));
  121. EXPECT_EQ(MUST(f2->evaluate(Vector<float> { 1.0f })), (Vector<float> { 0.0f, 8.0f }));
  122. }
  123. static PDF::PDFErrorOr<NonnullRefPtr<PDF::Function>> make_postscript_function(StringView program, Vector<float> domain, Vector<float> range)
  124. {
  125. return make_function(4, program.bytes(), move(domain), move(range));
  126. }
  127. static NonnullRefPtr<PDF::Function> check_postscript_function(StringView program, Vector<float> domain, Vector<float> range)
  128. {
  129. auto function = make_postscript_function(program, move(domain), move(range));
  130. if (function.is_error())
  131. FAIL(function.error().message());
  132. return function.value();
  133. }
  134. static void check_evaluate(StringView program, Vector<float> inputs, Vector<float> outputs)
  135. {
  136. Vector<float> domain;
  137. for (size_t i = 0; i < inputs.size(); ++i) {
  138. domain.append(-100.0f);
  139. domain.append(100.0f);
  140. }
  141. Vector<float> range;
  142. for (size_t i = 0; i < outputs.size(); ++i) {
  143. range.append(-100.0f);
  144. range.append(100.0f);
  145. }
  146. auto function = check_postscript_function(program, domain, range);
  147. auto result = function->evaluate(inputs);
  148. if (result.is_error())
  149. FAIL(result.error().message());
  150. EXPECT_EQ(result.value(), outputs);
  151. }
  152. TEST_CASE(postscript)
  153. {
  154. // Arithmetic operators
  155. check_evaluate("{ abs }"sv, { 0.5f }, { 0.5f });
  156. check_evaluate("{ add }"sv, { 0.25f, 0.5f }, { 0.75f });
  157. check_evaluate("{ atan }"sv, { 1.0f, 0.01f }, { AK::to_degrees(atan2f(0.01f, 1.0f)) });
  158. check_evaluate("{ ceiling }"sv, { 0.5f }, { 1.0f });
  159. check_evaluate("{ cos }"sv, { 1.0f }, { cosf(AK::to_radians(1.0f)) });
  160. check_evaluate("{ cvi }"sv, { 0.5f }, { 0.0f });
  161. check_evaluate("{ cvr }"sv, { 0.5f }, { 0.5f });
  162. check_evaluate("{ div }"sv, { 0.5f, 1.0f }, { 0.5f });
  163. check_evaluate("{ exp }"sv, { 0.0f }, { 1.0f });
  164. check_evaluate("{ floor }"sv, { 0.5f }, { 0.0f });
  165. check_evaluate("{ idiv }"sv, { 0.5f, 1.0f }, { 0.0f });
  166. check_evaluate("{ ln }"sv, { 10.0f }, { logf(10.0f) });
  167. check_evaluate("{ log }"sv, { 10.0f }, { log10f(10.0f) });
  168. check_evaluate("{ mod }"sv, { 0.5f, 0.25f }, { 0.0f });
  169. check_evaluate("{ mul }"sv, { 0.5f, 0.25f }, { 0.125f });
  170. check_evaluate("{ neg }"sv, { 0.5f }, { -0.5f });
  171. check_evaluate("{ round }"sv, { 0.5f }, { 1.0f });
  172. check_evaluate("{ sin }"sv, { 1.0f }, { sinf(AK::to_radians(1.0f)) });
  173. check_evaluate("{ sqrt }"sv, { 0.5f }, { sqrtf(0.5f) });
  174. check_evaluate("{ sub }"sv, { 0.5f, 0.25f }, { 0.25f });
  175. check_evaluate("{ truncate }"sv, { 0.5f }, { 0.0f });
  176. // Relational, boolean, and bitwise operators
  177. check_evaluate("{ and }"sv, { 0.0f, 1.0f }, { 0.0f });
  178. check_evaluate("{ bitshift }"sv, { 1.0f, 3.0f }, { 8.0f });
  179. check_evaluate("{ bitshift }"sv, { 8.0f, -2.0f }, { 2.0f });
  180. check_evaluate("{ eq }"sv, { 0.5f, 0.5f }, { 1.0f });
  181. check_evaluate("{ ge }"sv, { 0.5f, 0.5f }, { 1.0f });
  182. check_evaluate("{ gt }"sv, { 0.5f, 0.5f }, { 0.0f });
  183. check_evaluate("{ le }"sv, { 0.5f, 0.5f }, { 1.0f });
  184. check_evaluate("{ lt }"sv, { 0.5f, 0.5f }, { 0.0f });
  185. check_evaluate("{ ne }"sv, { 0.5f, 0.5f }, { 0.0f });
  186. check_evaluate("{ not }"sv, { 0.5f }, { 0.0f });
  187. check_evaluate("{ or }"sv, { 0.0f, 1.0f }, { 1.0f });
  188. check_evaluate("{ xor }"sv, { 0.0f, 1.0f }, { 1.0f });
  189. // Conditional operators
  190. check_evaluate("{ { 4 } if }"sv, { 1.0f }, { 4.0f });
  191. check_evaluate("{ { 4 } if }"sv, { 0.0f }, {});
  192. check_evaluate("{ { 4 } { 5 } ifelse }"sv, { 1.0f }, { 4.0f });
  193. check_evaluate("{ { 4 } { 5 } ifelse }"sv, { 0.0f }, { 5.0f });
  194. // Stack operators
  195. check_evaluate("{ 2 copy }"sv, { 8.0f, 0.5f, 1.0f }, { 8.0f, 0.5f, 1.0f, 0.5f, 1.0f });
  196. check_evaluate("{ dup }"sv, { 1.0f, 0.5f }, { 1.0f, 0.5f, 0.5f });
  197. check_evaluate("{ exch }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 0.5f, 1.0f });
  198. check_evaluate("{ 1 index }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 1.0f, 0.5f, 1.0f });
  199. check_evaluate("{ pop }"sv, { 8.0f, 1.0f, 0.5f }, { 8.0f, 1.0f });
  200. check_evaluate("{ 3 1 roll }"sv, { 0.5f, 1.0f, 2.0f }, { 2.0f, 0.5f, 1.0f });
  201. check_evaluate("{ 3 -1 roll }"sv, { 0.5f, 1.0f, 2.0f }, { 1.0f, 2.0f, 0.5f });
  202. }