From 49621ef5a825fc0a600284fa2c33775b330e2007 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Tue, 19 Dec 2023 16:15:08 -0500 Subject: [PATCH] Add qpdf-test-compare for comparing PDFs with different zlib --- CMakeLists.txt | 1 + compare-for-test/CMakeLists.txt | 15 ++ compare-for-test/compare.testcov | 9 + compare-for-test/qpdf-test-compare.cc | 215 ++++++++++++++++++ compare-for-test/qtest/compare.test | 93 ++++++++ .../qtest/compare/diff-data-enc.pdf | Bin 0 -> 1519 bytes .../qtest/compare/diff-data-size-unc.pdf | Bin 0 -> 843 bytes .../qtest/compare/diff-data-size.pdf | Bin 0 -> 847 bytes .../qtest/compare/diff-data-unc.pdf | Bin 0 -> 844 bytes compare-for-test/qtest/compare/diff-data.pdf | Bin 0 -> 849 bytes .../qtest/compare/diff-non-stream.pdf | Bin 0 -> 844 bytes .../qtest/compare/diff-num-objects.pdf | Bin 0 -> 882 bytes .../qtest/compare/diff-object-type.pdf | Bin 0 -> 765 bytes .../qtest/compare/diff-stream-dict.pdf | Bin 0 -> 844 bytes compare-for-test/qtest/compare/enc1.pdf | 41 ++++ compare-for-test/qtest/compare/enc2.pdf | 41 ++++ compare-for-test/qtest/compare/ostream1.pdf | Bin 0 -> 833 bytes compare-for-test/qtest/compare/ostream2.pdf | Bin 0 -> 843 bytes compare-for-test/qtest/compare/start.pdf | 47 ++++ compare-for-test/qtest/compare/zlib-9.pdf | Bin 0 -> 844 bytes compare-for-test/qtest/compare/zlib-ng.pdf | Bin 0 -> 848 bytes compare-for-test/qtest/compare/zlib.pdf | Bin 0 -> 844 bytes 22 files changed, 462 insertions(+) create mode 100644 compare-for-test/CMakeLists.txt create mode 100644 compare-for-test/compare.testcov create mode 100644 compare-for-test/qpdf-test-compare.cc create mode 100644 compare-for-test/qtest/compare.test create mode 100644 compare-for-test/qtest/compare/diff-data-enc.pdf create mode 100644 compare-for-test/qtest/compare/diff-data-size-unc.pdf create mode 100644 compare-for-test/qtest/compare/diff-data-size.pdf create mode 100644 compare-for-test/qtest/compare/diff-data-unc.pdf create mode 100644 compare-for-test/qtest/compare/diff-data.pdf create mode 100644 compare-for-test/qtest/compare/diff-non-stream.pdf create mode 100644 compare-for-test/qtest/compare/diff-num-objects.pdf create mode 100644 compare-for-test/qtest/compare/diff-object-type.pdf create mode 100644 compare-for-test/qtest/compare/diff-stream-dict.pdf create mode 100644 compare-for-test/qtest/compare/enc1.pdf create mode 100644 compare-for-test/qtest/compare/enc2.pdf create mode 100644 compare-for-test/qtest/compare/ostream1.pdf create mode 100644 compare-for-test/qtest/compare/ostream2.pdf create mode 100644 compare-for-test/qtest/compare/start.pdf create mode 100644 compare-for-test/qtest/compare/zlib-9.pdf create mode 100644 compare-for-test/qtest/compare/zlib-ng.pdf create mode 100644 compare-for-test/qtest/compare/zlib.pdf diff --git a/CMakeLists.txt b/CMakeLists.txt index 707db439..c264bfa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,6 +341,7 @@ add_test( # add_subdirectory order affects test order add_subdirectory(include) add_subdirectory(libqpdf) +add_subdirectory(compare-for-test) add_subdirectory(qpdf) add_subdirectory(libtests) add_subdirectory(examples) diff --git a/compare-for-test/CMakeLists.txt b/compare-for-test/CMakeLists.txt new file mode 100644 index 00000000..c5ebbbbc --- /dev/null +++ b/compare-for-test/CMakeLists.txt @@ -0,0 +1,15 @@ +# This directory is called compare-for-test rather than +# qpdf-test-compare to make shell completion easier. +add_executable(qpdf-test-compare qpdf-test-compare.cc) +target_link_libraries(qpdf-test-compare libqpdf) + +add_test( + NAME compare-for-test + COMMAND ${RUN_QTEST} + --top ${qpdf_SOURCE_DIR} + --bin $ + --bin $ # for Windows to find DLL + --code ${qpdf_SOURCE_DIR}/compare-for-test + --color ${QTEST_COLOR} + --show-on-failure ${SHOW_FAILED_TEST_OUTPUT} + --tc "${qpdf_SOURCE_DIR}/compare-for-test/*.cc") diff --git a/compare-for-test/compare.testcov b/compare-for-test/compare.testcov new file mode 100644 index 00000000..b58dd2c8 --- /dev/null +++ b/compare-for-test/compare.testcov @@ -0,0 +1,9 @@ +objects with different type 0 +different stream dictionaries 0 +uncompressing 0 +not uncompressing 0 +differing data size 1 +different data 1 +different non-stream 0 +different trailer 0 +ignore data for xref stream 0 diff --git a/compare-for-test/qpdf-test-compare.cc b/compare-for-test/qpdf-test-compare.cc new file mode 100644 index 00000000..7873f4a2 --- /dev/null +++ b/compare-for-test/qpdf-test-compare.cc @@ -0,0 +1,215 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +static char const* whoami = nullptr; + +void +usage() +{ + std::cerr << "Usage: " << whoami << " actual expected" << std::endl + << R"(Where "actual" is the actual output and "expected" is the expected)" + << std::endl + << "output of a test, compare the two PDF files. The files are considered" + << std::endl + << "to match if all their objects are identical except that, if a stream is" + << std::endl + << "compressed with FlateDecode, the uncompressed data must match." << std::endl + << std::endl + << "If the files match, the output is the expected file. Otherwise, it is" + << std::endl + << "the actual file. Read comments in the test suite for rationale." << std::endl; + exit(2); +} + +void +cleanEncryption(QPDF& q) +{ + auto enc = q.getTrailer().getKey("/Encrypt"); + if (!enc.isDictionary()) { + return; + } + enc.removeKey("/O"); + enc.removeKey("/OE"); + enc.removeKey("/U"); + enc.removeKey("/UE"); + enc.removeKey("/Perms"); +} + +std::string +compareObjects(std::string const& label, QPDFObjectHandle act, QPDFObjectHandle exp) +{ + if (act.getTypeCode() != exp.getTypeCode()) { + QTC::TC("compare", "objects with different type"); + return label + ": different types"; + } + if (act.isStream()) { + auto act_dict = act.getDict(); + auto exp_dict = exp.getDict(); + act_dict.removeKey("/Length"); + exp_dict.removeKey("/Length"); + if (act_dict.unparse() != exp_dict.unparse()) { + QTC::TC("compare", "different stream dictionaries"); + return label + ": stream dictionaries differ"; + } + if (act_dict.getKey("/Type").isNameAndEquals("/XRef")) { + QTC::TC("compare", "ignore data for xref stream"); + return ""; + } + auto act_filters = act_dict.getKey("/Filter"); + bool uncompress = false; + if (act_filters.isName()) { + act_filters = act_filters.wrapInArray(); + } + if (act_filters.isArray()) { + for (auto& filter: act_filters.aitems()) { + if (filter.isNameAndEquals("/FlateDecode")) { + uncompress = true; + break; + } + } + } + std::shared_ptr act_data; + std::shared_ptr exp_data; + if (uncompress) { + QTC::TC("compare", "uncompressing"); + act_data = act.getStreamData(); + exp_data = exp.getStreamData(); + } else { + QTC::TC("compare", "not uncompressing"); + act_data = act.getRawStreamData(); + exp_data = exp.getRawStreamData(); + } + if (act_data->getSize() != exp_data->getSize()) { + QTC::TC("compare", "differing data size", uncompress ? 0 : 1); + return label + ": stream data size differs"; + } + auto act_buf = act_data->getBuffer(); + auto exp_buf = exp_data->getBuffer(); + if (memcmp(act_buf, exp_buf, act_data->getSize()) != 0) { + QTC::TC("compare", "different data", uncompress ? 0 : 1); + return label + ": stream data differs"; + } + } else if (act.unparseResolved() != exp.unparseResolved()) { + QTC::TC("compare", "different non-stream"); + return label + ": object contents differ"; + } + return ""; +} + +std::string +compare(char const* actual_filename, char const* expected_filename) +{ + QPDF actual; + actual.processFile(actual_filename); + QPDF expected; + expected.processFile(expected_filename); + // The motivation behind this program is to compare files in a way that allows for + // differences in the exact bytes of zlib compression. If all zlib implementations produced + // exactly the same output, we would just be able to use straight comparison, but since they + // don't, we use this. As such, we are enforcing a standard of "sameness" that goes beyond + // showing semantic equivalence. The only difference we are allowing is compressed data. + + auto act_trailer = actual.getTrailer(); + auto exp_trailer = expected.getTrailer(); + act_trailer.removeKey("/Length"); + exp_trailer.removeKey("/Length"); + auto trailer_diff = compareObjects("trailer", act_trailer, exp_trailer); + if (!trailer_diff.empty()) { + QTC::TC("compare", "different trailer"); + return trailer_diff; + } + + cleanEncryption(actual); + cleanEncryption(expected); + + auto actual_objects = actual.getAllObjects(); + auto expected_objects = expected.getAllObjects(); + if (actual_objects.size() != expected_objects.size()) { + // Not exercised in the test suite since the trailers will differ in this case. + return "different number of objects"; + } + for (size_t i = 0; i < actual_objects.size(); ++i) { + auto act = actual_objects[i]; + auto exp = expected_objects[i]; + auto act_og = act.getObjGen(); + auto exp_og = exp.getObjGen(); + if (act_og != exp_og) { + // not reproduced in the test suite + return "different object IDs"; + } + auto ret = compareObjects(act_og.unparse(), act, exp); + if (!ret.empty()) { + return ret; + } + } + return ""; +} + +int +main(int argc, char* argv[]) +{ + if ((whoami = strrchr(argv[0], '/')) == nullptr) { + whoami = argv[0]; + } else { + ++whoami; + } + + if ((argc == 2) && (strcmp(argv[1], "--version") == 0)) { + std::cout << whoami << " from qpdf version " << QPDF::QPDFVersion() << std::endl; + exit(0); + } + + if (argc != 3) { + usage(); + } + + bool show_why = QUtil::get_env("QPDF_COMPARE_WHY"); + try { + char const* to_output; + auto actual = argv[1]; + auto expected = argv[2]; + auto difference = compare(actual, expected); + if (difference.empty()) { + // The files are identical; write the expected file. This way, tests can be written + // that compare the output of this program to the expected file. + to_output = expected; + } else { + if (show_why) { + std::cerr << difference << std::endl; + exit(2); + } + // The files differ; write the actual file. If it is determined that the actual file + // is correct because of changes that result in intended differences, this enables + // the output of this program to replace the expected file in the test suite. + to_output = actual; + } + auto f = QUtil::safe_fopen(to_output, "rb"); + QUtil::FileCloser fc(f); + QUtil::binary_stdout(); + auto out = std::make_unique("stdout", stdout); + unsigned char buf[2048]; + bool done = false; + while (!done) { + size_t len = fread(buf, 1, sizeof(buf), f); + if (len <= 0) { + done = true; + } else { + out->write(buf, len); + } + } + if (!difference.empty()) { + exit(2); + } + } catch (std::exception& e) { + std::cerr << whoami << ": " << e.what() << std::endl; + exit(2); + } + return 0; +} diff --git a/compare-for-test/qtest/compare.test b/compare-for-test/qtest/compare.test new file mode 100644 index 00000000..48625cf3 --- /dev/null +++ b/compare-for-test/qtest/compare.test @@ -0,0 +1,93 @@ +#!/usr/bin/env perl +require 5.008; +BEGIN { $^W = 1; } +use strict; + +chdir("compare") or die "chdir testdir failed: $!\n"; + +require TestDriver; + +my $td = new TestDriver('compare'); + +# The comparison tool is designed so that you can write tests that run +# `compare actual expected` and compare the result to expected. This +# allows you to just replace the actual file in a comparison with the +# comparison command. If the files match, the output is the expected +# file, which means that if the actual file is the expected file with +# different zlib compression, the test will pass. If the files differ, +# the actual output shown will be the real actual output. If it is +# determined to be correct and used to replace the expected output, +# the test will pass next time regardless of whether the same zlib +# implementation is used. + +# These files are the same file compressed with a different +# compression level and/or a different zlib implementation. +my @same = qw(zlib.pdf zlib-9.pdf zlib-ng.pdf); +my $comparisons = (scalar(@same) * (scalar(@same) + 1))/2; +my $n_tests = 2 * $comparisons; + +for (my $i = 0; $i < scalar(@same); $i++) +{ + for (my $j = $i; $j < scalar(@same); $j++) + { + # Make sure the files are byte-wise different (unless they are the same file). + $td->runtest("byte-wise compare $i and $j", + {$td->COMMAND => "cmp $same[$i] $same[$j]"}, + {$td->REGEXP => ".*", $td->EXIT_STATUS => $i == $j ? 0 : "!0"}); + # Make sure they match. This is how compare should be used: + # the expected output is the same file as the second argument + # to the command. + $td->runtest("compare $i and $j", + {$td->COMMAND => "qpdf-test-compare $same[$i] $same[$j]"}, + {$td->FILE => $same[$j], $td->EXIT_STATUS => 0}); + } +} + +my @diff = ( + ["diff-num-objects.pdf", "trailer: object contents differ"], + ["diff-non-stream.pdf", "3,0: object contents differ"], + ["diff-data-size.pdf", "4,0: stream data size differs"], + ["diff-data.pdf", "4,0: stream data differs"], + ["diff-data-size-unc.pdf", "5,0: stream data size differs"], + ["diff-data-unc.pdf", "5,0: stream data differs"], + ["diff-stream-dict.pdf", "4,0: stream dictionaries differ"], + ["diff-object-type.pdf", "6,0: different types"], + ); +$n_tests += 2 * scalar(@diff); + +foreach my $f (@diff) +{ + # In a real test, the expected output would be the expected file + # as above. Here, we are actually testing the comparison tool to + # verify that it returns a non-zero status and the actual file + # when there is mismatch. Don't copy this test. + $td->runtest("$f->[0] is different", + {$td->COMMAND => "qpdf-test-compare $f->[0] zlib.pdf"}, + {$td->FILE => $f->[0], $td->EXIT_STATUS => 2}); + $td->runtest("$f->[0] is different (why)", + {$td->COMMAND => "env QPDF_COMPARE_WHY=1" . + " qpdf-test-compare $f->[0] zlib.pdf"}, + {$td->STRING => "$f->[1]\n", $td->EXIT_STATUS => 2}, + $td->NORMALIZE_NEWLINES); +} + +# Repeat for encrypted files. +$n_tests += 3; +$td->runtest("byte-wise compare encrypted files", + {$td->COMMAND => "cmp enc1.pdf enc2.pdf"}, + {$td->REGEXP => ".*", $td->EXIT_STATUS => "!0"}); +$td->runtest("compare encrypted files (same)", + {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf enc2.pdf"}, + {$td->FILE => "enc2.pdf", $td->EXIT_STATUS => 0}); +$td->runtest("compare encrypted files (different)", + {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare enc1.pdf diff-data-enc.pdf"}, + {$td->STRING => "4,0: stream data differs\n", $td->EXIT_STATUS => 2}, + $td->NORMALIZE_NEWLINES); + +# Object streams +$n_tests += 1; +$td->runtest("compare object stream files (same)", + {$td->COMMAND => "env QPDF_COMPARE_WHY=1 qpdf-test-compare ostream1.pdf ostream2.pdf"}, + {$td->FILE => "ostream2.pdf", $td->EXIT_STATUS => 0}); + +$td->report($n_tests); diff --git a/compare-for-test/qtest/compare/diff-data-enc.pdf b/compare-for-test/qtest/compare/diff-data-enc.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae2b23b0df08256646823bc212586021417afe45 GIT binary patch literal 1519 zcma)6O=w(I6c&mK17_pS7P*@&6zaSGKR6CelZ;9m6KB$>l!Eu&du}>9eG}filvHAo zZgf#-M1&aVLRY$Rr!HK$5xP>L3m2sY5$#4P?p!G9d6P^gq+R$P@4frZz2CXtIp@1) zdTFkGoIgVw)8G90$v+K7C>i8$G@4D4E%{X#5{{M*$(Apz0m){4<@?T-@6;vt8#Pu#Lf-*?)9UuuI_AYz2Ex& ztH=JneYw+{?%%qzaOd&o{<@D2y6*I-K zH!*bA^J=7{T1}{vT~UoZOk`mWY%tp%6|q~zz0u5ib$6Y~pp!r=0h&HxQ^O z5FP)3il0D7MSBer6+I;-6&+&MIiEx9!mBraZ|BXM&Zs}!VRv29`TFP6UqZnJJvk=b zE;u7OQxz~o#^5BcPZc=3(#W}Cy!JyGe_Y0D3Z^OD)Bp)M)lQHr^=ElQ!05vmLDtfb3FR~iYG36y0v%Z z^S2Lg&+c8narNxS*3D~2ciyEhzPvxZeChY|?O!;pbK3dbtiR1G*_wJUA$Tzb=0TDX zfPjGrDI_VLZ;iB(M&E|ym<$q|#Q)mXaHHLmm8yr~JW%tO%H&fC&Y(aqc`*a$Szg>P zs=NjE7ZX!QZ3D+BSGm^;ZF0*}WyFPmxEBuy-{(GLaDh>@XdftAOyHz9Fv@TbHZUe| z4>vF#psfwe6Jd*)Qs#4v%cefo+AdGW1pzpFeK_cPEcED<^2sC%+$aqq$y_&+ yR75o7A`9a#rylhqCeTe71rcXF^aK+g=OJf7$A|gN-uO*7r7L$0K^(xqlJy`-Z;wz~5 z3n~gKy8VR};v47?cbs(+!npA0+&Sky&h5ve$s_)llK!{fU;YpV6sp-d84SRQ)j~JG z5lO&F-(P5Oj+9Z$Y5`G1beY+QHrx@8s#R%#f%B}$8aM&bQcpYbMsG*8;T^R!x-^#M zwk)sXzR+2rhSeG)6hFy0_#p>Wja7}5uE0b$)vBIj#kTfIg^~8cK(!*v`w|;%U`vV7d!@L=tZSgRx*h?@>31D&t+=Vp9yU#%e4AKnm z_v6YaQ$2w6oQzZJ#=qjW=}vs88r=@Wd8(I}+7xpI&bY*WigE$Y>!N&8HpLD&Ud>Ev zw>2H@+<4zA?A%+|Iwur-LbnH`=LrvT*kTNOv-JGV6R&RdyNM?L96&Xz;png!~0&wdG#` literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/diff-data-unc.pdf b/compare-for-test/qtest/compare/diff-data-unc.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b79f7afbcd2672db1ed36590d851313ce22c5346 GIT binary patch literal 844 zcmZ8fJ&)5s5CtKm)0T)IFeef5A%VTS_S%*r3vx-s2@oN%1k&k>O}x(eWbDJJ!;;Cd`#hCl6J=)JNdBD3WGcmH5r1RztNYVr58`E|q*v)*mbKb2|C{ibpnkva^5b z^S2LgPw(ztyL|d%=lYeSTkql*U*4Zwyzu+k)n7QRGuqkQjKA)cd`o>05x|=%FbARp z&mIHeQ;1?b-%Jx%j_ zd6l-nY&F+))+TYxaua;5&_=f|RYGj=h<*Nma9!>~0_PY-kLH2A#RQJJgHeWy(7~9% zMeJbQLt7op5kZUTQl=T^Wn!Neh1tY>&06$!t53 yR0P!LBJsmMrw(-kCeV!^cmZeJcLWm-=RRj%;D(2rm}IHzF}OmIUT^exO#T5M{p7F! literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/diff-data.pdf b/compare-for-test/qtest/compare/diff-data.pdf new file mode 100644 index 0000000000000000000000000000000000000000..04216efab1bb58e5d0c401e621f26d6880324004 GIT binary patch literal 849 zcmZ8fOODe(5QSaTLaaDIZ6ZDrxIebrmLf}Jl86Wp#$$=aXcnEg9UKLF#_m91jW`7> zZovwUz!lIOf*qpT8IMD{7jC`sd-ZuWj3=|l{0Sw)AAi36B@8H3i!~XIz=_pLH^31| zz)3$|XmC!HQJZQ7QABi^*&l7VBb-#*(f|YJd66}62BM{&cjUcZPqpEmS{hv%%W_+m z*KuF!tWe`>hY^a`XB=e60aasFBc&@a(M`3jmsqi_eO6(leK7D_sVKs#4@)^{!lvvh zd7;adc?%vzkz!+Xjo*zjdZL$ArY)&4wN~%Q?rTGSC-JWjBBlKGV1AXvR3=pNcrds4 z;LiQK>qnon%kN(Qh_rqv7@3~f%B#)pO#J01E<@CX$`lw zqoI5ETZP`gU9EFMK@xg%!1p}iK@K+-foyT7N!Ck+yu`2@~JE)QI`WMZ+%B@HtfDo$yxm>;r0_<0bG1ap}e mav!@1LKzA!0@vrhD?}i;487=lZ^LN literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/diff-non-stream.pdf b/compare-for-test/qtest/compare/diff-non-stream.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2e7e6e80a9bbe7d771e8d1e886a3ed26accad5d3 GIT binary patch literal 844 zcmZ8fJ&)5s5CtKm)0XIdz#tLvAszPa+G|^iEXXAhCqRUpC6G>6Y~pp!r=0h&HxQ^O z5FP)3il0D7MSBer6+I;-6&+&MIiEx9!mBraZ|BXM&Zs}!VRv29`TFP6UqZnJJvk=b zE;u7OQxz~o#^5BcPZc=3(#W}Cy!JyGe_Y0D3Z^OD)Bp)M)lQHr^=ElQ!05vmLDtfb3FR~iYG36y0v%Z z^S2Lg&+c8narNxS*3D~2ciyEhzPvxZeChY|?O!;pbK3dbtiR1G`I>q!A%HhiU>+nH zo&z)zQbRFD9nW+9r-!u7a->+US<0%7_aAaW5VazR!Kg-~yxQ(LPYLn7~nQV3gq^Y+y{_ zB5q(jKwBG_C!!WJrOfA;myLa_wcW&eb@%f(3IcHU`f$+oSm@Cy<&#MkxKSEJlDTds ysfcLEMHa?gPCe>JOrV=E3L?&U=m{n~&O^?E$d3bYG8#+&1Fw7Fyi7TD1#tkfT|-|A*C&FtZF^4rdYA9eW)?gTquY}Dvq)0 z%~Cd+uqoS09;k9=j==L#BrlAr@Lx!y`f93EWl6QElzc`OA8PVrJo@&MCoX%uvv=Xs z*Y|Hu?_9Zh@$~!7wM$1g-=@z$zdJd9?$^`HKXF=r-~QK5#sh403-d(uALfgVcczkgfv(!+7;A0!wOR1}{I!A*oV`9AbUhY&bV~VT zk_B#*29ad0n@K7n8gh|^ahFq%`VkY@VHgDwXFT)-6CURwXF=r0hf6bMWt!3Wp+`EM I!J{Gh3)5!pu>b%7 literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/diff-object-type.pdf b/compare-for-test/qtest/compare/diff-object-type.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8380e88d0e02d08e5b99a26a087dfac82223a431 GIT binary patch literal 765 zcmZ8fJ&)8d5CtKmlS{-87$jDFNRZf0>{wbw=x%SN6ClEp0_k*xcjN5sX^D@-Cl)FS zM8`j%;wR8i(O!c@MNdgdMTZ#YF1JhUBBM8XZ{Ey!kd4Oo*!_?UzW(|2mrw}7PLIfN z2tlUjrU8b?1cLnav4LPmJH51XNK;~}!vE;g9bw0wR1PQv4;MuP`@mc3K}SB*TT^{{ zO|6`%oM%NXEAF_DO|j71c7>S`ub>R1Vt}fdu94CioS4R*)H8JKy^k$s+JJ&+rP35# zZ(7-C!k6rvJTleX9YPeN$YSYCjo+nqW@KizFrL)7+UOT#^|2v8C)xK`JP+B^t-ULs zzkPUn`ryXRtEWGuHT<^A#HOTV9A|Ao^!r=8Eu_t!7UH`KRt0$7;>iy$vC zmJCEfAulk#omr=yy#x6X+0Feb{ulQhdvU6|HLYq>k`N>bFAj(}<}s9Tfl)N&4^(SR z;B0yrWw^N>#st2c9>yj5=wXpiYs}SpvBUxUJx#3jPp5rr&lYbCNC@^uus@7g644pu z(`hL~RY;{-7?zp}MH4Q{Bpq@Z(O5Bo-6TpX&Ug|DCL+!g&ZLUdgR{Bn+O=bd5=jPw I-6v!655}#^TL1t6 literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/diff-stream-dict.pdf b/compare-for-test/qtest/compare/diff-stream-dict.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cf40d323655d918d2ada8758d3d5c1bcb125c9f7 GIT binary patch literal 844 zcmZ8fJ&)5s5CtKm)0T)IFi1pvNMP@-y|$&uf?N`D0z}AJ0x7y;6R&eV<-CWzfj~up z==cXz`~*5G+G~)g=qV|w=n%6`d_J;nR&V^?zL__jQGa-c-E~Rl>z_}52?ZDQ^oVr3 z;Ed#4RlpD#gOj{IQQ+)KBNuuOaZFT^+8=GXA?)g9VSs}3Fi$I(0I#VB4SB8CQf;}V z7Dg4uvb>t*H{8c6&1Fxou;St;D1#tkfT|-|BBe1nR+V0sGjwdd4>eZm3k6Y2#WA`* zZ{=JQ_Q}S{BUQ}JA$UHDGQV_Z%^-CyMFof$Igu_hqvFQFTT7#xp?9C^Q*sbS{vGCZnnSeC%Lt>`K^}_KnE0< z2T6wafPn}pBq`o+jjctkNOc4*i9G(5obK~1QQ> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >> +endobj +4 0 obj +<< /Filter /FlateDecode /Length 64 >> +stream +*8FTbp~0(Ѣ#'őדp;ˆ*ZBjHU[gendstream +endobj +5 0 obj +<< /Length 80 /Filter /FlateDecode >> +stream +*8FTbp~0(Ѣ#'őד́i4bzKST$ EzaI<@,w6edendstream +endobj +6 0 obj +<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> +endobj +7 0 obj +<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O /OE <9423f87d42392b07fc90b6a2329545a1c877ecec680adc8cbc80a5ad5c3abb6c> /P -4 /Perms <84770c5fdc078585b95e8592bb0b38a3> /R 6 /StmF /StdCF /StrF /StdCF /U <4165270c9c8795068aba2bae6f89673992c6ed0e0c2d2bfca6189293a5ba3c4817f0c7a4eb476c53ac29382cea765534> /UE <7991ebbe79a40d5dfb1a1bc87394a81dbefc6ab9a1b19ee7845099ed6e7de14b> /V 5 >> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000261 00000 n +0000000395 00000 n +0000000545 00000 n +0000000642 00000 n +trailer << /Root 1 0 R /Size 8 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] /Encrypt 7 0 R >> +startxref +1189 +%%EOF diff --git a/compare-for-test/qtest/compare/enc2.pdf b/compare-for-test/qtest/compare/enc2.pdf new file mode 100644 index 00000000..5a025491 --- /dev/null +++ b/compare-for-test/qtest/compare/enc2.pdf @@ -0,0 +1,41 @@ +%PDF-2.0 +% +1 0 obj +<< /Pages 2 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >> +endobj +4 0 obj +<< /Filter /FlateDecode /Length 80 >> +stream +*8FTbp~൐_7a7ҧ'\ }??OsvZ> +stream +*8FTbp~൐_7a7ҧ'\ߥR1"'GRrЭHY_&ˢ2 ߴs> +endobj +7 0 obj +<< /CF << /StdCF << /AuthEvent /DocOpen /CFM /AESV3 /Length 32 >> >> /Filter /Standard /Length 256 /O <08cc676b1f1cc805ee97abf33aab0f77cb195093c52b65ebf04b1dce93531d8d11b6cd60da17599e4d3679513b957140> /OE /P -4 /Perms <973bd88c774165b5e58f722b3ced7bf4> /R 6 /StmF /StdCF /StrF /StdCF /U <8203fcce3446c8747d515ac3368fb817e0b7a290e1298d2a0246cd3b559d4544aebba6df7a97f0c8e74f98638f658468> /UE <689a534cf6e2ea26b9a5f9073ccfcf268700cc129779a5d1bbabc9eae77c72f0> /V 5 >> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000261 00000 n +0000000411 00000 n +0000000561 00000 n +0000000658 00000 n +trailer << /Root 1 0 R /Size 8 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] /Encrypt 7 0 R >> +startxref +1205 +%%EOF diff --git a/compare-for-test/qtest/compare/ostream1.pdf b/compare-for-test/qtest/compare/ostream1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b340ae33b36f397fab249007a3cfc3f910c5ebe2 GIT binary patch literal 833 zcmY!laBZ^4|D>$ol3WFSpVYkck_-hy zOA`fsx6GW9)FL3AlUS1KlA4^K0#xXy0G25#E>SQtP_VP(DlREXP0Z!0nB&{$$aTm- z!1epQNB0$cqoZ4c0s>hCySVg@xaK%>dMK%h?%g}tBgClN;Q!g#o)ZAEPetC?oco^H9 zwNJk)&dp-I5wv|-@Gf?1E!)dsf2DpueAIMgb%hBVv*i6lk-;xh^HQLG0kS}$V}=w; zSi=GuSSF?@;ZV%=FeuYx zg=hss1tTDiRnQO0&j%(Spshg)`oWo1sS1_~`kpQd(KaSV7AA(thQ>)rY32r&Ddv`m zMg|6HiH2sDh8D(VX%==i#)c+_rj|x#rpBfgmgbhmM#dHN)LM&_2LcCjdt zk(|W9q~^v}C-AYek@G~di_$;iS$|kJbu|k0r1CI0xv-dUVFX8UNn%k+MNw)Rm#K*n Lm#V6(zZ(|-p$sGw literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/ostream2.pdf b/compare-for-test/qtest/compare/ostream2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..27d6b2c20a536c89af1a8072f09c6129bf444f04 GIT binary patch literal 843 zcmY!laBZ^4|D>$ol3WFSpVYkck_-hy zOLGN%x6GW9)FL3AlUS1KlA4^K0#xXyU;>gUDlSnlGElIy<0>vGN=?k=s+i+@?ta!` z1(D+)f7=~>&wJ%hW*EnzC^NR?fK5*NPWm}T98Q*f8OOeTb8gN)$o;YAha9)Z6bi&w-jhU zv8~fovi?HG*?WH%w6`1y6U``dog;JBN9L2b)u+6f?4LUJh96Jdt8s-hL-zdPcYCVx zZB+H{z4+#PkdN(AE4z8rJcV=9=HI;i`|$H3UQMB3E%9K-*JtGqMFzi2%}arL2gm{i zkQq`yVGRywc$t`@1Vu5|!=Qi*<;EcfMu8lj%$v^kHk@!!RAD`FjYC~1L#rjFaA#Wq zBg4lC5lk!1k*tK8Zfb}7o#AV`5}sVwh}b zoRpMiZeW>WZkcFgV33w*Xl7|>VQiLWVP|7(Xkut;X=G+YyF2#Bz5__MvCkZ0MZZTAYTG=)4e*Q>5rA6(n6n6=9(kHv}$ aBS?x%5{pVIic-_KOie7fR8?L5-M9b>Yb`ne literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/start.pdf b/compare-for-test/qtest/compare/start.pdf new file mode 100644 index 00000000..79001f24 --- /dev/null +++ b/compare-for-test/qtest/compare/start.pdf @@ -0,0 +1,47 @@ +%PDF-2.0 +% +1 0 obj +<< /Pages 2 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >> +endobj +4 0 obj +<< /Length 48 /Filter /FlateDecode >> +stream +BT + /F1 24 Tf + 72 720 Td + (WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW) Tj +ET +endstream +endobj +5 0 obj +<< /Length 43 >> +stream +BT + /F1 24 Tf + 72 681 Td + (Potato) Tj +ET +endstream +endobj +6 0 obj +<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Subtype /Type1 /Type /Font >> +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000261 00000 n +0000000379 00000 n +0000000471 00000 n +trailer << /Root 1 0 R /Size 7 /ID [<42841c13bbf709d79a200fa1691836f8><31415926535897932384626433832795>] >> +startxref +568 +%%EOF diff --git a/compare-for-test/qtest/compare/zlib-9.pdf b/compare-for-test/qtest/compare/zlib-9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..16187f315b1daf95fda9dd65bb11bd9cd1f77e20 GIT binary patch literal 844 zcmZ8fJ&)5s5CtKm)0XIdz#tLvAszPa+G|^iEXXAhCqRUpC6G>6Y~pp!r=0h&HxQ^O z5FLMlpFl@Ndkqp51sx?N6&+&MIiEx9!mBraZ|BXM&Zs}!VRv29`SR!EUqZnJJvk=b zE;u7OQxz~o#^5BcPZc=3(#W}Cy!JyGe_Y0D3Z^OD)Bp)M)lQHr^=ElQ!05vmOm=;b3FR?iYG36y0v%Z z)7KAg&+c8narNx`*3D~2ciyEhKEFS`eChY|?O!;pbK3dbtiR1G`I>q!A%HhiU>+nH zo&yFVq>!X|zBSTD8hsm*V=_o=6#t7`$BlSTR;r$c^FYmCDw9toID-Ps; zMclx6fVMU;Ped(dN}10wFB|(h9-n6a?Vx_2HoFvCyMa$|sX7aHBMcBy-(N yQW4RRi!6-0oO;xcm_RpS6hxfy&=X8}oQIqRkslwfVv?n)$KVS=I-S9jA^8VUeC1yN literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/zlib-ng.pdf b/compare-for-test/qtest/compare/zlib-ng.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9d8c432968eb753b79e4ccaa637300e773d4c8f4 GIT binary patch literal 848 zcmZ8gyN=U96ooEwiTHrqL_8$$JnR`;iY$@cL_~lvUP~aYwwT1@tXILa*b@lUh_9gH zFR1thegRQYQqdvqIO|QwxbWy)pK~AQdYB$hAFzkS8-Dxq<*!G9fSF%-qY?P2TIv=U zA{qGk`%4Y}k+N!KmXIW#t_$~}3-^R0v#u>r@Sjvg3#Y(4>RC_T>g}j5yrb4u*VeIu zjurOYXS%4=*laLD@DY@Oj2WP6sv4y91!lT6>t=x!yV|D)Bi)69=%kVatKKhVuL+m3 zujHw&m-ZZj7)7d;)eXK^%IagiFokxc);3zb_BNke??;w?f5&seUJPbGvy{k;NR|#} z4jnw{(MFfHH9FwQ-|>=al4d5L$)KtvSs0`GTI zW0f`cAiwY?xwGScao2S(K31*nCgMNVtGC)#3kCk9#)hhT3I5BfepI*B4merQZRfXh z9sS&z-zn_u+cdiL2uP1y9}r>4Lnz@Iqu8T6Q138-<37MB!(}+Yn80N`z<7i^aDWAJ zk82xMt8lW~}wZEaGG?ZyyF{DFp(=Tq+=>(}LC literal 0 HcmV?d00001 diff --git a/compare-for-test/qtest/compare/zlib.pdf b/compare-for-test/qtest/compare/zlib.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9a24beb43e190e89c82f22b0801cc0a36192a91b GIT binary patch literal 844 zcmZ8fJ&)5s5CtKm)0XIdz#tLvAszPa+G|^iEXXAhCqRUpC6G>6Y~pp!r=0h&HxQ^O z5FP)3il0D7MSBer6+I;-6&+&MIiEx9!mBraZ|BXM&Zs}!VRv29`TFP6UqZnJJvk=b zE;u7OQxz~o#^5BcPZc=3(#W}Cy!JyGe_Y0D3Z^OD)Bp)M)lQHr^=ElQ!05vmLDtfb3FR~iYG36y0v%Z z^S2Lg&+c8narNxS*3D~2ciyEhzPvxZeChY|?O!;pbK3dbtiR1G`I>q!A%HhiU>+nH zo&yFVq>!X|zBSTD8hsm*V=_o=6#t7`$BlSTR;r$c^FYmCDw9toID-Ps; zMclx6fVMU;Ped(dN}10wFB|(h9-n6a?Vx_2HoFvCyMa$|sX7aHBMcBy-(N yQW4RRi!6-0oO;xcm_RpS6hxfy&=X8}oQIqRkslwfVv?n)$KVS=I-S9jA^8W