Commit f049a77c5962a0e41723bc83900656ece821d916

Authored by Jay Berkenbilt
1 parent 04fc7c4b

Add additional information when listing attachments

ChangeLog
1 2022-05-30 Jay Berkenbilt <ejb@ql.org> 1 2022-05-30 Jay Berkenbilt <ejb@ql.org>
2 2
  3 + * Include additional information in --list-attachments --verbose
  4 + and in --json --json-key=attachments.
  5 +
3 * Add QUtil::qpdf_time_to_iso8601 and QUtil::pdf_time_to_iso8601 6 * Add QUtil::qpdf_time_to_iso8601 and QUtil::pdf_time_to_iso8601
4 for converting PDF/qpdf timestamps to ISO-8601 date format. 7 for converting PDF/qpdf timestamps to ISO-8601 date format.
5 8
@@ -72,9 +72,6 @@ Remaining work: @@ -72,9 +72,6 @@ Remaining work:
72 72
73 * --encryption: show recovered user password when available 73 * --encryption: show recovered user password when available
74 74
75 - * --list-attachments: add information from --verbose. Add to a  
76 - "details" subkey.  
77 -  
78 * Consider having --check, --show-encryption, etc., just select the 75 * Consider having --check, --show-encryption, etc., just select the
79 right keys when in json mode. I don't think I want check on by 76 right keys when in json mode. I don't think I want check on by
80 default, so that might be different. 77 default, so that might be different.
job.sums
@@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431 @@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431
14 libqpdf/qpdf/auto_job_json_init.hh 5f6b53e3c81d4b54ce5c4cf9c3f52d0c02f987c53bf8841c0280367bad23e335 14 libqpdf/qpdf/auto_job_json_init.hh 5f6b53e3c81d4b54ce5c4cf9c3f52d0c02f987c53bf8841c0280367bad23e335
15 libqpdf/qpdf/auto_job_schema.hh 9d543cd4a43eafffc2c4b8a6fee29e399c271c52cb6f7d417ae5497b3c1127dc 15 libqpdf/qpdf/auto_job_schema.hh 9d543cd4a43eafffc2c4b8a6fee29e399c271c52cb6f7d417ae5497b3c1127dc
16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
17 -manual/cli.rst e7c35f8183d015d7fe074e38baed4c89bad827fd9c23b4cafd73d562df82ab1b 17 +manual/cli.rst 82ead389c03bbf5e0498bd0571a11dc06544d591f4e4454c00322e3473fc556d
libqpdf/QPDFJob.cc
@@ -993,8 +993,16 @@ QPDFJob::doListAttachments(QPDF&amp; pdf) @@ -993,8 +993,16 @@ QPDFJob::doListAttachments(QPDF&amp; pdf)
993 } 993 }
994 cout << " all data streams:" << std::endl; 994 cout << " all data streams:" << std::endl;
995 for (auto i2: efoh->getEmbeddedFileStreams().ditems()) { 995 for (auto i2: efoh->getEmbeddedFileStreams().ditems()) {
  996 + auto efs = QPDFEFStreamObjectHelper(i2.second);
996 cout << " " << i2.first << " -> " 997 cout << " " << i2.first << " -> "
997 - << i2.second.getObjGen() << std::endl; 998 + << efs.getObjectHandle().getObjGen() << std::endl;
  999 + cout << " creation date: " << efs.getCreationDate()
  1000 + << std::endl
  1001 + << " modification date: " << efs.getModDate()
  1002 + << std::endl
  1003 + << " mime type: " << efs.getSubtype() << std::endl
  1004 + << " checksum: "
  1005 + << QUtil::hex_encode(efs.getChecksum()) << std::endl;
998 } 1006 }
999 }); 1007 });
1000 } 1008 }
@@ -1445,6 +1453,22 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1445,6 +1453,22 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1445 void 1453 void
1446 QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) 1454 QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf)
1447 { 1455 {
  1456 + auto to_iso8601 = [](std::string const& d) {
  1457 + // Convert PDF date to iso8601 if not empty; if empty, return
  1458 + // empty.
  1459 + std::string iso8601;
  1460 + QUtil::pdf_time_to_iso8601(d, iso8601);
  1461 + return iso8601;
  1462 + };
  1463 +
  1464 + auto null_or_string = [](std::string const& s) {
  1465 + if (s.empty()) {
  1466 + return JSON::makeNull();
  1467 + } else {
  1468 + return JSON::makeString(s);
  1469 + }
  1470 + };
  1471 +
1448 JSON j_attachments = JSON::makeDictionary(); 1472 JSON j_attachments = JSON::makeDictionary();
1449 QPDFEmbeddedFileDocumentHelper efdh(pdf); 1473 QPDFEmbeddedFileDocumentHelper efdh(pdf);
1450 for (auto const& iter: efdh.getEmbeddedFiles()) { 1474 for (auto const& iter: efdh.getEmbeddedFiles()) {
@@ -1459,6 +1483,31 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1459,6 +1483,31 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1459 j_details.addDictionaryMember( 1483 j_details.addDictionaryMember(
1460 "preferredcontents", 1484 "preferredcontents",
1461 JSON::makeString(fsoh->getEmbeddedFileStream().unparse())); 1485 JSON::makeString(fsoh->getEmbeddedFileStream().unparse()));
  1486 + j_details.addDictionaryMember(
  1487 + "description", null_or_string(fsoh->getDescription()));
  1488 + auto j_names =
  1489 + j_details.addDictionaryMember("names", JSON::makeDictionary());
  1490 + for (auto const& i2: fsoh->getFilenames()) {
  1491 + j_names.addDictionaryMember(i2.first, JSON::makeString(i2.second));
  1492 + }
  1493 + auto j_streams =
  1494 + j_details.addDictionaryMember("streams", JSON::makeDictionary());
  1495 + for (auto i2: fsoh->getEmbeddedFileStreams().ditems()) {
  1496 + auto efs = QPDFEFStreamObjectHelper(i2.second);
  1497 + auto j_stream =
  1498 + j_streams.addDictionaryMember(i2.first, JSON::makeDictionary());
  1499 + j_stream.addDictionaryMember(
  1500 + "creationdate",
  1501 + null_or_string(to_iso8601(efs.getCreationDate())));
  1502 + j_stream.addDictionaryMember(
  1503 + "modificationdate",
  1504 + null_or_string(to_iso8601(efs.getCreationDate())));
  1505 + j_stream.addDictionaryMember(
  1506 + "mimetype", null_or_string(efs.getSubtype()));
  1507 + j_stream.addDictionaryMember(
  1508 + "checksum",
  1509 + null_or_string(QUtil::hex_encode(efs.getChecksum())));
  1510 + }
1462 } 1511 }
1463 JSON::writeDictionaryItem(p, first, "attachments", j_attachments, 0); 1512 JSON::writeDictionaryItem(p, first, "attachments", j_attachments, 0);
1464 } 1513 }
@@ -1640,7 +1689,19 @@ QPDFJob::json_schema(int json_version, std::set&lt;std::string&gt;* keys) @@ -1640,7 +1689,19 @@ QPDFJob::json_schema(int json_version, std::set&lt;std::string&gt;* keys)
1640 "<attachment-key>": { 1689 "<attachment-key>": {
1641 "filespec": "object containing the file spec", 1690 "filespec": "object containing the file spec",
1642 "preferredcontents": "most preferred embedded file stream", 1691 "preferredcontents": "most preferred embedded file stream",
1643 - "preferredname": "most preferred file name" 1692 + "preferredname": "most preferred file name",
  1693 + "description": "description of attachment",
  1694 + "names": {
  1695 + "<name-key>": "file name for key"
  1696 + },
  1697 + "streams": {
  1698 + "<stream-key>": {
  1699 + "creationdate": "ISO-8601 creation date or null",
  1700 + "modificationdate": "ISO-8601 modification date or null",
  1701 + "mimetype": "mime type or null",
  1702 + "checksum": "MD5 checksum or null"
  1703 + }
  1704 + }
1644 } 1705 }
1645 })")); 1706 })"));
1646 } 1707 }
manual/cli.rst
@@ -3124,7 +3124,10 @@ Related Options @@ -3124,7 +3124,10 @@ Related Options
3124 :qpdf:ref:`--verbose`, additional information, including preferred 3124 :qpdf:ref:`--verbose`, additional information, including preferred
3125 file name, description, dates, and more are also displayed. The key 3125 file name, description, dates, and more are also displayed. The key
3126 is usually but not always equal to the file name and is needed by 3126 is usually but not always equal to the file name and is needed by
3127 - some of the other options. See also :ref:`attachments`. 3127 + some of the other options. See also :ref:`attachments`. Note that
  3128 + this option displays dates in PDF timestamp syntax. When attachment
  3129 + information is included in json output (see :ref:`--json`), dates
  3130 + are shown in ISO-8601 format.
3128 3131
3129 .. qpdf:option:: --show-attachment=key 3132 .. qpdf:option:: --show-attachment=key
3130 3133
manual/release-notes.rst
@@ -96,6 +96,13 @@ For a detailed list of changes, please see the file @@ -96,6 +96,13 @@ For a detailed list of changes, please see the file
96 - See :ref:`breaking-crypto-api` for specific details, and see 96 - See :ref:`breaking-crypto-api` for specific details, and see
97 :ref:`weak-crypto` for a general discussion. 97 :ref:`weak-crypto` for a general discussion.
98 98
  99 + - CLI Enhancements
  100 +
  101 + - ``qpdf --list-attachments --verbose`` include some additional
  102 + information about attachments. Additional information about
  103 + attachments is also included in the ``attachments`` json key
  104 + with ``--json``.
  105 +
99 - Library Enhancements 106 - Library Enhancements
100 107
101 - New methods ``insertItemAndGet``, ``appendItemAndGet``, 108 - New methods ``insertItemAndGet``, ``appendItemAndGet``,
@@ -120,6 +127,9 @@ For a detailed list of changes, please see the file @@ -120,6 +127,9 @@ For a detailed list of changes, please see the file
120 - Add new ``Pipeline`` type ``Pl_String`` to append to a 127 - Add new ``Pipeline`` type ``Pl_String`` to append to a
121 ``std::string``. 128 ``std::string``.
122 129
  130 + - Add methods to QUtil for converting PDF timestamps and QPDFTime
  131 + objects to ISO-8601 timestamps.
  132 +
123 - Enhance JSON class to better support incrementally reading and 133 - Enhance JSON class to better support incrementally reading and
124 writing large amounts of data without having to keep everything 134 writing large amounts of data without having to keep everything
125 in memory. 135 in memory.
qpdf/qtest/attachments.test
@@ -189,7 +189,8 @@ $td-&gt;runtest(&quot;add attachments: current date&quot;, @@ -189,7 +189,8 @@ $td-&gt;runtest(&quot;add attachments: current date&quot;,
189 $td->NORMALIZE_NEWLINES); 189 $td->NORMALIZE_NEWLINES);
190 $td->runtest("list attachments", 190 $td->runtest("list attachments",
191 {$td->COMMAND => 191 {$td->COMMAND =>
192 - "qpdf --password=u --list-attachments a.pdf --verbose"}, 192 + "qpdf --password=u --list-attachments a.pdf --verbose",
  193 + $td->FILTER => "perl filter-attachment-date.pl"},
193 {$td->FILE => "list-attachments-4.out", $td->EXIT_STATUS => 0}, 194 {$td->FILE => "list-attachments-4.out", $td->EXIT_STATUS => 0},
194 $td->NORMALIZE_NEWLINES); 195 $td->NORMALIZE_NEWLINES);
195 # The object to show here is the one in list-attachments-4.out 196 # The object to show here is the one in list-attachments-4.out
qpdf/qtest/json.test
@@ -26,6 +26,7 @@ my @json_files = ( @@ -26,6 +26,7 @@ my @json_files = (
26 ['field-types', ['--show-encryption-key']], 26 ['field-types', ['--show-encryption-key']],
27 ['image-streams', ['--decode-level=all']], 27 ['image-streams', ['--decode-level=all']],
28 ['image-streams', ['--decode-level=specialized']], 28 ['image-streams', ['--decode-level=specialized']],
  29 + ['attachment-fields', []],
29 ['page-labels-and-outlines', ['--json-key=objects']], 30 ['page-labels-and-outlines', ['--json-key=objects']],
30 ['page-labels-and-outlines', ['--json-key=pages']], 31 ['page-labels-and-outlines', ['--json-key=pages']],
31 ['page-labels-and-outlines', ['--json-key=pagelabels']], 32 ['page-labels-and-outlines', ['--json-key=pagelabels']],
qpdf/qtest/qpdf/attachment-fields.pdf 0 → 100644
  1 +%PDF-1.3
  2 +%¿÷¢þ
  3 +%QDF-1.0
  4 +
  5 +%% Original object ID: 1 0
  6 +1 0 obj
  7 +<<
  8 + /Names <<
  9 + /EmbeddedFiles 2 0 R
  10 + >>
  11 + /PageMode /UseAttachments
  12 + /Pages 3 0 R
  13 + /Type /Catalog
  14 +>>
  15 +endobj
  16 +
  17 +%% Original object ID: 2 0
  18 +2 0 obj
  19 +<<
  20 + /Names [
  21 + (a.txt)
  22 + 4 0 R
  23 + <feff03c0002e007400780074>
  24 + 5 0 R
  25 + ]
  26 +>>
  27 +endobj
  28 +
  29 +%% Original object ID: 3 0
  30 +3 0 obj
  31 +<<
  32 + /Count 1
  33 + /Kids [
  34 + 6 0 R
  35 + ]
  36 + /Type /Pages
  37 +>>
  38 +endobj
  39 +
  40 +%% Original object ID: 4 0
  41 +4 0 obj
  42 +<<
  43 + /EF <<
  44 + /F 7 0 R
  45 + /UF 7 0 R
  46 + >>
  47 + /F (a.txt)
  48 + /Type /Filespec
  49 + /UF (a.txt)
  50 +>>
  51 +endobj
  52 +
  53 +%% Original object ID: 5 0
  54 +5 0 obj
  55 +<<
  56 + /Desc (Two filenames)
  57 + /EF <<
  58 + /F 9 0 R
  59 + /UF 9 0 R
  60 + >>
  61 + /F (pi.txt)
  62 + /Type /Filespec
  63 + /UF <feff03c0002e007400780074>
  64 +>>
  65 +endobj
  66 +
  67 +%% Page 1
  68 +%% Original object ID: 6 0
  69 +6 0 obj
  70 +<<
  71 + /Contents 11 0 R
  72 + /MediaBox [
  73 + 0
  74 + 0
  75 + 612
  76 + 792
  77 + ]
  78 + /Parent 3 0 R
  79 + /Resources <<
  80 + /Font <<
  81 + /F1 13 0 R
  82 + >>
  83 + /ProcSet 14 0 R
  84 + >>
  85 + /Type /Page
  86 +>>
  87 +endobj
  88 +
  89 +%% Original object ID: 7 0
  90 +7 0 obj
  91 +<<
  92 + /Params <<
  93 + /Size 7
  94 + >>
  95 + /Type /EmbeddedFile
  96 + /Length 8 0 R
  97 +>>
  98 +stream
  99 +potato
  100 +endstream
  101 +endobj
  102 +
  103 +8 0 obj
  104 +7
  105 +endobj
  106 +
  107 +%% Original object ID: 8 0
  108 +9 0 obj
  109 +<<
  110 + /Params <<
  111 + /CheckSum <e561f9248d7563d15dd93457b02ebbb6>
  112 + /CreationDate (D:20220530094116-05'00')
  113 + /ModDate (D:20220530094116-05'00')
  114 + /Size 7
  115 + >>
  116 + /Subtype /text#2fplain
  117 + /Type /EmbeddedFile
  118 + /Length 10 0 R
  119 +>>
  120 +stream
  121 +potato
  122 +endstream
  123 +endobj
  124 +
  125 +10 0 obj
  126 +7
  127 +endobj
  128 +
  129 +%% Contents for page 1
  130 +%% Original object ID: 9 0
  131 +11 0 obj
  132 +<<
  133 + /Length 12 0 R
  134 +>>
  135 +stream
  136 +BT
  137 + /F1 24 Tf
  138 + 72 720 Td
  139 + (Potato) Tj
  140 +ET
  141 +endstream
  142 +endobj
  143 +
  144 +12 0 obj
  145 +44
  146 +endobj
  147 +
  148 +%% Original object ID: 10 0
  149 +13 0 obj
  150 +<<
  151 + /BaseFont /Helvetica
  152 + /Encoding /WinAnsiEncoding
  153 + /Subtype /Type1
  154 + /Type /Font
  155 +>>
  156 +endobj
  157 +
  158 +%% Original object ID: 11 0
  159 +14 0 obj
  160 +[
  161 + /PDF
  162 + /Text
  163 +]
  164 +endobj
  165 +
  166 +xref
  167 +0 15
  168 +0000000000 65535 f
  169 +0000000052 00000 n
  170 +0000000203 00000 n
  171 +0000000330 00000 n
  172 +0000000429 00000 n
  173 +0000000564 00000 n
  174 +0000000753 00000 n
  175 +0000000975 00000 n
  176 +0000001089 00000 n
  177 +0000001134 00000 n
  178 +0000001406 00000 n
  179 +0000001475 00000 n
  180 +0000001576 00000 n
  181 +0000001624 00000 n
  182 +0000001759 00000 n
  183 +trailer <<
  184 + /Root 1 0 R
  185 + /Size 15
  186 + /ID [<3d1a89e08f9d6b3e1f787d04fceed440><4e13de38230bb10a03e49285a742c392>]
  187 +>>
  188 +startxref
  189 +1795
  190 +%%EOF
qpdf/qtest/qpdf/filter-attachment-date.pl 0 → 100644
  1 +use warnings;
  2 +use strict;
  3 +
  4 +while (<>)
  5 +{
  6 + s/D:\d{14}\S+/<date>/;
  7 + print;
  8 +}
qpdf/qtest/qpdf/json-attachment-fields-v1.out 0 → 100644
  1 +{
  2 + "version": 1,
  3 + "parameters": {
  4 + "decodelevel": "generalized"
  5 + },
  6 + "pages": [
  7 + {
  8 + "contents": [
  9 + "11 0 R"
  10 + ],
  11 + "images": [],
  12 + "label": null,
  13 + "object": "6 0 R",
  14 + "outlines": [],
  15 + "pageposfrom1": 1
  16 + }
  17 + ],
  18 + "pagelabels": [],
  19 + "acroform": {
  20 + "fields": [],
  21 + "hasacroform": false,
  22 + "needappearances": false
  23 + },
  24 + "attachments": {
  25 + "a.txt": {
  26 + "description": null,
  27 + "filespec": "4 0 R",
  28 + "names": {
  29 + "/F": "a.txt",
  30 + "/UF": "a.txt"
  31 + },
  32 + "preferredcontents": "7 0 R",
  33 + "preferredname": "a.txt",
  34 + "streams": {
  35 + "/F": {
  36 + "checksum": null,
  37 + "creationdate": null,
  38 + "mimetype": null,
  39 + "modificationdate": null
  40 + },
  41 + "/UF": {
  42 + "checksum": null,
  43 + "creationdate": null,
  44 + "mimetype": null,
  45 + "modificationdate": null
  46 + }
  47 + }
  48 + },
  49 + "π.txt": {
  50 + "description": "Two filenames",
  51 + "filespec": "5 0 R",
  52 + "names": {
  53 + "/F": "pi.txt",
  54 + "/UF": "π.txt"
  55 + },
  56 + "preferredcontents": "9 0 R",
  57 + "preferredname": "π.txt",
  58 + "streams": {
  59 + "/F": {
  60 + "checksum": "e561f9248d7563d15dd93457b02ebbb6",
  61 + "creationdate": "2022-05-30T09:41:16-05:00",
  62 + "mimetype": "text/plain",
  63 + "modificationdate": "2022-05-30T09:41:16-05:00"
  64 + },
  65 + "/UF": {
  66 + "checksum": "e561f9248d7563d15dd93457b02ebbb6",
  67 + "creationdate": "2022-05-30T09:41:16-05:00",
  68 + "mimetype": "text/plain",
  69 + "modificationdate": "2022-05-30T09:41:16-05:00"
  70 + }
  71 + }
  72 + }
  73 + },
  74 + "encrypt": {
  75 + "capabilities": {
  76 + "accessibility": true,
  77 + "extract": true,
  78 + "moddifyannotations": true,
  79 + "modify": true,
  80 + "modifyassembly": true,
  81 + "modifyforms": true,
  82 + "modifyother": true,
  83 + "printhigh": true,
  84 + "printlow": true
  85 + },
  86 + "encrypted": false,
  87 + "ownerpasswordmatched": false,
  88 + "parameters": {
  89 + "P": 0,
  90 + "R": 0,
  91 + "V": 0,
  92 + "bits": 0,
  93 + "filemethod": "none",
  94 + "key": null,
  95 + "method": "none",
  96 + "streammethod": "none",
  97 + "stringmethod": "none"
  98 + },
  99 + "userpasswordmatched": false
  100 + },
  101 + "outlines": [],
  102 + "objects": {
  103 + "1 0 R": {
  104 + "/Names": {
  105 + "/EmbeddedFiles": "2 0 R"
  106 + },
  107 + "/PageMode": "/UseAttachments",
  108 + "/Pages": "3 0 R",
  109 + "/Type": "/Catalog"
  110 + },
  111 + "2 0 R": {
  112 + "/Names": [
  113 + "a.txt",
  114 + "4 0 R",
  115 + "π.txt",
  116 + "5 0 R"
  117 + ]
  118 + },
  119 + "3 0 R": {
  120 + "/Count": 1,
  121 + "/Kids": [
  122 + "6 0 R"
  123 + ],
  124 + "/Type": "/Pages"
  125 + },
  126 + "4 0 R": {
  127 + "/EF": {
  128 + "/F": "7 0 R",
  129 + "/UF": "7 0 R"
  130 + },
  131 + "/F": "a.txt",
  132 + "/Type": "/Filespec",
  133 + "/UF": "a.txt"
  134 + },
  135 + "5 0 R": {
  136 + "/Desc": "Two filenames",
  137 + "/EF": {
  138 + "/F": "9 0 R",
  139 + "/UF": "9 0 R"
  140 + },
  141 + "/F": "pi.txt",
  142 + "/Type": "/Filespec",
  143 + "/UF": "π.txt"
  144 + },
  145 + "6 0 R": {
  146 + "/Contents": "11 0 R",
  147 + "/MediaBox": [
  148 + 0,
  149 + 0,
  150 + 612,
  151 + 792
  152 + ],
  153 + "/Parent": "3 0 R",
  154 + "/Resources": {
  155 + "/Font": {
  156 + "/F1": "13 0 R"
  157 + },
  158 + "/ProcSet": "14 0 R"
  159 + },
  160 + "/Type": "/Page"
  161 + },
  162 + "7 0 R": {
  163 + "/Length": "8 0 R",
  164 + "/Params": {
  165 + "/Size": 7
  166 + },
  167 + "/Type": "/EmbeddedFile"
  168 + },
  169 + "8 0 R": 7,
  170 + "9 0 R": {
  171 + "/Length": "10 0 R",
  172 + "/Params": {
  173 + "/CheckSum": "åaù$“ucÑ]Ù4W°.»¶",
  174 + "/CreationDate": "D:20220530094116-05'00'",
  175 + "/ModDate": "D:20220530094116-05'00'",
  176 + "/Size": 7
  177 + },
  178 + "/Subtype": "/text#2fplain",
  179 + "/Type": "/EmbeddedFile"
  180 + },
  181 + "10 0 R": 7,
  182 + "11 0 R": {
  183 + "/Length": "12 0 R"
  184 + },
  185 + "12 0 R": 44,
  186 + "13 0 R": {
  187 + "/BaseFont": "/Helvetica",
  188 + "/Encoding": "/WinAnsiEncoding",
  189 + "/Subtype": "/Type1",
  190 + "/Type": "/Font"
  191 + },
  192 + "14 0 R": [
  193 + "/PDF",
  194 + "/Text"
  195 + ],
  196 + "trailer": {
  197 + "/ID": [
  198 + "=ˆ›à‘šk>˜x}\u0004üîÔ@",
  199 + "N\u0013Þ8#\u000b±\n\u0003ä™–§BÙ"
  200 + ],
  201 + "/Root": "1 0 R",
  202 + "/Size": 15
  203 + }
  204 + },
  205 + "objectinfo": {
  206 + "1 0 R": {
  207 + "stream": {
  208 + "filter": null,
  209 + "is": false,
  210 + "length": null
  211 + }
  212 + },
  213 + "2 0 R": {
  214 + "stream": {
  215 + "filter": null,
  216 + "is": false,
  217 + "length": null
  218 + }
  219 + },
  220 + "3 0 R": {
  221 + "stream": {
  222 + "filter": null,
  223 + "is": false,
  224 + "length": null
  225 + }
  226 + },
  227 + "4 0 R": {
  228 + "stream": {
  229 + "filter": null,
  230 + "is": false,
  231 + "length": null
  232 + }
  233 + },
  234 + "5 0 R": {
  235 + "stream": {
  236 + "filter": null,
  237 + "is": false,
  238 + "length": null
  239 + }
  240 + },
  241 + "6 0 R": {
  242 + "stream": {
  243 + "filter": null,
  244 + "is": false,
  245 + "length": null
  246 + }
  247 + },
  248 + "7 0 R": {
  249 + "stream": {
  250 + "filter": null,
  251 + "is": true,
  252 + "length": 7
  253 + }
  254 + },
  255 + "8 0 R": {
  256 + "stream": {
  257 + "filter": null,
  258 + "is": false,
  259 + "length": null
  260 + }
  261 + },
  262 + "9 0 R": {
  263 + "stream": {
  264 + "filter": null,
  265 + "is": true,
  266 + "length": 7
  267 + }
  268 + },
  269 + "10 0 R": {
  270 + "stream": {
  271 + "filter": null,
  272 + "is": false,
  273 + "length": null
  274 + }
  275 + },
  276 + "11 0 R": {
  277 + "stream": {
  278 + "filter": null,
  279 + "is": true,
  280 + "length": 44
  281 + }
  282 + },
  283 + "12 0 R": {
  284 + "stream": {
  285 + "filter": null,
  286 + "is": false,
  287 + "length": null
  288 + }
  289 + },
  290 + "13 0 R": {
  291 + "stream": {
  292 + "filter": null,
  293 + "is": false,
  294 + "length": null
  295 + }
  296 + },
  297 + "14 0 R": {
  298 + "stream": {
  299 + "filter": null,
  300 + "is": false,
  301 + "length": null
  302 + }
  303 + }
  304 + }
  305 +}
qpdf/qtest/qpdf/json-attachment-fields-v2.out 0 → 100644
  1 +{
  2 + "version": 2,
  3 + "parameters": {
  4 + "decodelevel": "generalized"
  5 + },
  6 + "pages": [
  7 + {
  8 + "contents": [
  9 + "11 0 R"
  10 + ],
  11 + "images": [],
  12 + "label": null,
  13 + "object": "6 0 R",
  14 + "outlines": [],
  15 + "pageposfrom1": 1
  16 + }
  17 + ],
  18 + "pagelabels": [],
  19 + "acroform": {
  20 + "fields": [],
  21 + "hasacroform": false,
  22 + "needappearances": false
  23 + },
  24 + "attachments": {
  25 + "a.txt": {
  26 + "description": null,
  27 + "filespec": "4 0 R",
  28 + "names": {
  29 + "/F": "a.txt",
  30 + "/UF": "a.txt"
  31 + },
  32 + "preferredcontents": "7 0 R",
  33 + "preferredname": "a.txt",
  34 + "streams": {
  35 + "/F": {
  36 + "checksum": null,
  37 + "creationdate": null,
  38 + "mimetype": null,
  39 + "modificationdate": null
  40 + },
  41 + "/UF": {
  42 + "checksum": null,
  43 + "creationdate": null,
  44 + "mimetype": null,
  45 + "modificationdate": null
  46 + }
  47 + }
  48 + },
  49 + "π.txt": {
  50 + "description": "Two filenames",
  51 + "filespec": "5 0 R",
  52 + "names": {
  53 + "/F": "pi.txt",
  54 + "/UF": "π.txt"
  55 + },
  56 + "preferredcontents": "9 0 R",
  57 + "preferredname": "π.txt",
  58 + "streams": {
  59 + "/F": {
  60 + "checksum": "e561f9248d7563d15dd93457b02ebbb6",
  61 + "creationdate": "2022-05-30T09:41:16-05:00",
  62 + "mimetype": "text/plain",
  63 + "modificationdate": "2022-05-30T09:41:16-05:00"
  64 + },
  65 + "/UF": {
  66 + "checksum": "e561f9248d7563d15dd93457b02ebbb6",
  67 + "creationdate": "2022-05-30T09:41:16-05:00",
  68 + "mimetype": "text/plain",
  69 + "modificationdate": "2022-05-30T09:41:16-05:00"
  70 + }
  71 + }
  72 + }
  73 + },
  74 + "encrypt": {
  75 + "capabilities": {
  76 + "accessibility": true,
  77 + "extract": true,
  78 + "modify": true,
  79 + "modifyannotations": true,
  80 + "modifyassembly": true,
  81 + "modifyforms": true,
  82 + "modifyother": true,
  83 + "printhigh": true,
  84 + "printlow": true
  85 + },
  86 + "encrypted": false,
  87 + "ownerpasswordmatched": false,
  88 + "parameters": {
  89 + "P": 0,
  90 + "R": 0,
  91 + "V": 0,
  92 + "bits": 0,
  93 + "filemethod": "none",
  94 + "key": null,
  95 + "method": "none",
  96 + "streammethod": "none",
  97 + "stringmethod": "none"
  98 + },
  99 + "userpasswordmatched": false
  100 + },
  101 + "outlines": [],
  102 + "objects": {
  103 + "obj:1 0 R": {
  104 + "value": {
  105 + "/Names": {
  106 + "/EmbeddedFiles": "2 0 R"
  107 + },
  108 + "/PageMode": "/UseAttachments",
  109 + "/Pages": "3 0 R",
  110 + "/Type": "/Catalog"
  111 + }
  112 + },
  113 + "obj:2 0 R": {
  114 + "value": {
  115 + "/Names": [
  116 + "u:a.txt",
  117 + "4 0 R",
  118 + "u:π.txt",
  119 + "5 0 R"
  120 + ]
  121 + }
  122 + },
  123 + "obj:3 0 R": {
  124 + "value": {
  125 + "/Count": 1,
  126 + "/Kids": [
  127 + "6 0 R"
  128 + ],
  129 + "/Type": "/Pages"
  130 + }
  131 + },
  132 + "obj:4 0 R": {
  133 + "value": {
  134 + "/EF": {
  135 + "/F": "7 0 R",
  136 + "/UF": "7 0 R"
  137 + },
  138 + "/F": "u:a.txt",
  139 + "/Type": "/Filespec",
  140 + "/UF": "u:a.txt"
  141 + }
  142 + },
  143 + "obj:5 0 R": {
  144 + "value": {
  145 + "/Desc": "u:Two filenames",
  146 + "/EF": {
  147 + "/F": "9 0 R",
  148 + "/UF": "9 0 R"
  149 + },
  150 + "/F": "u:pi.txt",
  151 + "/Type": "/Filespec",
  152 + "/UF": "u:π.txt"
  153 + }
  154 + },
  155 + "obj:6 0 R": {
  156 + "value": {
  157 + "/Contents": "11 0 R",
  158 + "/MediaBox": [
  159 + 0,
  160 + 0,
  161 + 612,
  162 + 792
  163 + ],
  164 + "/Parent": "3 0 R",
  165 + "/Resources": {
  166 + "/Font": {
  167 + "/F1": "13 0 R"
  168 + },
  169 + "/ProcSet": "14 0 R"
  170 + },
  171 + "/Type": "/Page"
  172 + }
  173 + },
  174 + "obj:7 0 R": {
  175 + "stream": {
  176 + "dict": {
  177 + "/Length": "8 0 R",
  178 + "/Params": {
  179 + "/Size": 7
  180 + },
  181 + "/Type": "/EmbeddedFile"
  182 + }
  183 + }
  184 + },
  185 + "obj:8 0 R": {
  186 + "value": 7
  187 + },
  188 + "obj:9 0 R": {
  189 + "stream": {
  190 + "dict": {
  191 + "/Length": "10 0 R",
  192 + "/Params": {
  193 + "/CheckSum": "b:e561f9248d7563d15dd93457b02ebbb6",
  194 + "/CreationDate": "u:D:20220530094116-05'00'",
  195 + "/ModDate": "u:D:20220530094116-05'00'",
  196 + "/Size": 7
  197 + },
  198 + "/Subtype": "/text/plain",
  199 + "/Type": "/EmbeddedFile"
  200 + }
  201 + }
  202 + },
  203 + "obj:10 0 R": {
  204 + "value": 7
  205 + },
  206 + "obj:11 0 R": {
  207 + "stream": {
  208 + "dict": {
  209 + "/Length": "12 0 R"
  210 + }
  211 + }
  212 + },
  213 + "obj:12 0 R": {
  214 + "value": 44
  215 + },
  216 + "obj:13 0 R": {
  217 + "value": {
  218 + "/BaseFont": "/Helvetica",
  219 + "/Encoding": "/WinAnsiEncoding",
  220 + "/Subtype": "/Type1",
  221 + "/Type": "/Font"
  222 + }
  223 + },
  224 + "obj:14 0 R": {
  225 + "value": [
  226 + "/PDF",
  227 + "/Text"
  228 + ]
  229 + },
  230 + "trailer": {
  231 + "value": {
  232 + "/ID": [
  233 + "b:3d1a89e08f9d6b3e1f787d04fceed440",
  234 + "b:4e13de38230bb10a03e49285a742c392"
  235 + ],
  236 + "/Root": "1 0 R",
  237 + "/Size": 15
  238 + }
  239 + }
  240 + }
  241 +}
qpdf/qtest/qpdf/list-attachments-1.out
@@ -5,7 +5,15 @@ auto-1 -&gt; 8,0 @@ -5,7 +5,15 @@ auto-1 -&gt; 8,0
5 /UF -> auto-1 5 /UF -> auto-1
6 all data streams: 6 all data streams:
7 /F -> 8,0 7 /F -> 8,0
  8 + creation date: D:20210210091359-05'00'
  9 + modification date: D:20210210141359Z
  10 + mime type: text/plain
  11 + checksum: a857d18d3fc23ad412122ef040733331
8 /UF -> 8,0 12 /UF -> 8,0
  13 + creation date: D:20210210091359-05'00'
  14 + modification date: D:20210210141359Z
  15 + mime type: text/plain
  16 + checksum: a857d18d3fc23ad412122ef040733331
9 auto-3 -> 10,0 17 auto-3 -> 10,0
10 description: two words 18 description: two words
11 preferred name: auto-Three.txt 19 preferred name: auto-Three.txt
@@ -14,7 +22,15 @@ auto-3 -&gt; 10,0 @@ -14,7 +22,15 @@ auto-3 -&gt; 10,0
14 /UF -> auto-Three.txt 22 /UF -> auto-Three.txt
15 all data streams: 23 all data streams:
16 /F -> 10,0 24 /F -> 10,0
  25 + creation date: D:20210210091359-05'00'
  26 + modification date: D:20210210141359Z
  27 + mime type:
  28 + checksum: d6c7ac7cf295ae133fea186cfd068dab
17 /UF -> 10,0 29 /UF -> 10,0
  30 + creation date: D:20210210091359-05'00'
  31 + modification date: D:20210210141359Z
  32 + mime type:
  33 + checksum: d6c7ac7cf295ae133fea186cfd068dab
18 auto-Two -> 12,0 34 auto-Two -> 12,0
19 preferred name: auto-2 35 preferred name: auto-2
20 all names: 36 all names:
@@ -22,4 +38,12 @@ auto-Two -&gt; 12,0 @@ -22,4 +38,12 @@ auto-Two -&gt; 12,0
22 /UF -> auto-2 38 /UF -> auto-2
23 all data streams: 39 all data streams:
24 /F -> 12,0 40 /F -> 12,0
  41 + creation date: D:20210210091359-05'00'
  42 + modification date: D:20210210141359Z
  43 + mime type:
  44 + checksum: 9f991a5669c47a94f9350f53e3953e57
25 /UF -> 12,0 45 /UF -> 12,0
  46 + creation date: D:20210210091359-05'00'
  47 + modification date: D:20210210141359Z
  48 + mime type:
  49 + checksum: 9f991a5669c47a94f9350f53e3953e57
qpdf/qtest/qpdf/list-attachments-2.out
@@ -5,7 +5,15 @@ @@ -5,7 +5,15 @@
5 /UF -> auto-1 5 /UF -> auto-1
6 all data streams: 6 all data streams:
7 /F -> 11,0 7 /F -> 11,0
  8 + creation date: D:20210210091359-05'00'
  9 + modification date: D:20210210141359Z
  10 + mime type: text/plain
  11 + checksum: a857d18d3fc23ad412122ef040733331
8 /UF -> 11,0 12 /UF -> 11,0
  13 + creation date: D:20210210091359-05'00'
  14 + modification date: D:20210210141359Z
  15 + mime type: text/plain
  16 + checksum: a857d18d3fc23ad412122ef040733331
9 1-auto-3 -> 13,0 17 1-auto-3 -> 13,0
10 description: two words 18 description: two words
11 preferred name: auto-Three.txt 19 preferred name: auto-Three.txt
@@ -14,7 +22,15 @@ @@ -14,7 +22,15 @@
14 /UF -> auto-Three.txt 22 /UF -> auto-Three.txt
15 all data streams: 23 all data streams:
16 /F -> 13,0 24 /F -> 13,0
  25 + creation date: D:20210210091359-05'00'
  26 + modification date: D:20210210141359Z
  27 + mime type:
  28 + checksum: d6c7ac7cf295ae133fea186cfd068dab
17 /UF -> 13,0 29 /UF -> 13,0
  30 + creation date: D:20210210091359-05'00'
  31 + modification date: D:20210210141359Z
  32 + mime type:
  33 + checksum: d6c7ac7cf295ae133fea186cfd068dab
18 1-auto-Two -> 15,0 34 1-auto-Two -> 15,0
19 preferred name: auto-2 35 preferred name: auto-2
20 all names: 36 all names:
@@ -22,7 +38,15 @@ @@ -22,7 +38,15 @@
22 /UF -> auto-2 38 /UF -> auto-2
23 all data streams: 39 all data streams:
24 /F -> 15,0 40 /F -> 15,0
  41 + creation date: D:20210210091359-05'00'
  42 + modification date: D:20210210141359Z
  43 + mime type:
  44 + checksum: 9f991a5669c47a94f9350f53e3953e57
25 /UF -> 15,0 45 /UF -> 15,0
  46 + creation date: D:20210210091359-05'00'
  47 + modification date: D:20210210141359Z
  48 + mime type:
  49 + checksum: 9f991a5669c47a94f9350f53e3953e57
26 auto-1 -> 17,0 50 auto-1 -> 17,0
27 preferred name: auto-1 51 preferred name: auto-1
28 all names: 52 all names:
@@ -30,7 +54,15 @@ auto-1 -&gt; 17,0 @@ -30,7 +54,15 @@ auto-1 -&gt; 17,0
30 /UF -> auto-1 54 /UF -> auto-1
31 all data streams: 55 all data streams:
32 /F -> 17,0 56 /F -> 17,0
  57 + creation date: D:20210210091359-05'00'
  58 + modification date: D:20210210141359Z
  59 + mime type: text/plain
  60 + checksum: a857d18d3fc23ad412122ef040733331
33 /UF -> 17,0 61 /UF -> 17,0
  62 + creation date: D:20210210091359-05'00'
  63 + modification date: D:20210210141359Z
  64 + mime type: text/plain
  65 + checksum: a857d18d3fc23ad412122ef040733331
34 auto-3 -> 19,0 66 auto-3 -> 19,0
35 description: two words 67 description: two words
36 preferred name: auto-Three.txt 68 preferred name: auto-Three.txt
@@ -39,7 +71,15 @@ auto-3 -&gt; 19,0 @@ -39,7 +71,15 @@ auto-3 -&gt; 19,0
39 /UF -> auto-Three.txt 71 /UF -> auto-Three.txt
40 all data streams: 72 all data streams:
41 /F -> 19,0 73 /F -> 19,0
  74 + creation date: D:20210210091359-05'00'
  75 + modification date: D:20210210141359Z
  76 + mime type:
  77 + checksum: d6c7ac7cf295ae133fea186cfd068dab
42 /UF -> 19,0 78 /UF -> 19,0
  79 + creation date: D:20210210091359-05'00'
  80 + modification date: D:20210210141359Z
  81 + mime type:
  82 + checksum: d6c7ac7cf295ae133fea186cfd068dab
43 auto-Two -> 21,0 83 auto-Two -> 21,0
44 preferred name: auto-2 84 preferred name: auto-2
45 all names: 85 all names:
@@ -47,4 +87,12 @@ auto-Two -&gt; 21,0 @@ -47,4 +87,12 @@ auto-Two -&gt; 21,0
47 /UF -> auto-2 87 /UF -> auto-2
48 all data streams: 88 all data streams:
49 /F -> 21,0 89 /F -> 21,0
  90 + creation date: D:20210210091359-05'00'
  91 + modification date: D:20210210141359Z
  92 + mime type:
  93 + checksum: 9f991a5669c47a94f9350f53e3953e57
50 /UF -> 21,0 94 /UF -> 21,0
  95 + creation date: D:20210210091359-05'00'
  96 + modification date: D:20210210141359Z
  97 + mime type:
  98 + checksum: 9f991a5669c47a94f9350f53e3953e57
qpdf/qtest/qpdf/list-attachments-3.out
@@ -5,7 +5,15 @@ auto-1 -&gt; 8,0 @@ -5,7 +5,15 @@ auto-1 -&gt; 8,0
5 /UF -> auto-2 5 /UF -> auto-2
6 all data streams: 6 all data streams:
7 /F -> 8,0 7 /F -> 8,0
  8 + creation date: D:20210210091359-05'00'
  9 + modification date: D:20210210141359Z
  10 + mime type:
  11 + checksum: 9f991a5669c47a94f9350f53e3953e57
8 /UF -> 8,0 12 /UF -> 8,0
  13 + creation date: D:20210210091359-05'00'
  14 + modification date: D:20210210141359Z
  15 + mime type:
  16 + checksum: 9f991a5669c47a94f9350f53e3953e57
9 auto-3 -> 10,0 17 auto-3 -> 10,0
10 description: two words 18 description: two words
11 preferred name: auto-Three.txt 19 preferred name: auto-Three.txt
@@ -14,7 +22,15 @@ auto-3 -&gt; 10,0 @@ -14,7 +22,15 @@ auto-3 -&gt; 10,0
14 /UF -> auto-Three.txt 22 /UF -> auto-Three.txt
15 all data streams: 23 all data streams:
16 /F -> 10,0 24 /F -> 10,0
  25 + creation date: D:20210210091359-05'00'
  26 + modification date: D:20210210141359Z
  27 + mime type:
  28 + checksum: d6c7ac7cf295ae133fea186cfd068dab
17 /UF -> 10,0 29 /UF -> 10,0
  30 + creation date: D:20210210091359-05'00'
  31 + modification date: D:20210210141359Z
  32 + mime type:
  33 + checksum: d6c7ac7cf295ae133fea186cfd068dab
18 auto-Two -> 12,0 34 auto-Two -> 12,0
19 preferred name: auto-2 35 preferred name: auto-2
20 all names: 36 all names:
@@ -22,4 +38,12 @@ auto-Two -&gt; 12,0 @@ -22,4 +38,12 @@ auto-Two -&gt; 12,0
22 /UF -> auto-2 38 /UF -> auto-2
23 all data streams: 39 all data streams:
24 /F -> 12,0 40 /F -> 12,0
  41 + creation date: D:20210210091359-05'00'
  42 + modification date: D:20210210141359Z
  43 + mime type:
  44 + checksum: 9f991a5669c47a94f9350f53e3953e57
25 /UF -> 12,0 45 /UF -> 12,0
  46 + creation date: D:20210210091359-05'00'
  47 + modification date: D:20210210141359Z
  48 + mime type:
  49 + checksum: 9f991a5669c47a94f9350f53e3953e57
qpdf/qtest/qpdf/list-attachments-4.out
@@ -5,4 +5,12 @@ auto-1 -&gt; 6,0 @@ -5,4 +5,12 @@ auto-1 -&gt; 6,0
5 /UF -> auto-1 5 /UF -> auto-1
6 all data streams: 6 all data streams:
7 /F -> 6,0 7 /F -> 6,0
  8 + creation date: <date>
  9 + modification date: <date>
  10 + mime type:
  11 + checksum: a857d18d3fc23ad412122ef040733331
8 /UF -> 6,0 12 /UF -> 6,0
  13 + creation date: <date>
  14 + modification date: <date>
  15 + mime type:
  16 + checksum: a857d18d3fc23ad412122ef040733331
qpdf/qtest/qpdf/test76-json.out
@@ -5,19 +5,76 @@ @@ -5,19 +5,76 @@
5 }, 5 },
6 "attachments": { 6 "attachments": {
7 "att1": { 7 "att1": {
  8 + "description": "some text",
8 "filespec": "4 0 R", 9 "filespec": "4 0 R",
  10 + "names": {
  11 + "/F": "att1.txt",
  12 + "/UF": "att1.txt"
  13 + },
9 "preferredcontents": "8 0 R", 14 "preferredcontents": "8 0 R",
10 - "preferredname": "att1.txt" 15 + "preferredname": "att1.txt",
  16 + "streams": {
  17 + "/F": {
  18 + "checksum": "2e10f186a4cdf5be438747f4bdc2d4d4",
  19 + "creationdate": "2021-02-07T19:11:21-05:00",
  20 + "mimetype": "text/plain",
  21 + "modificationdate": "2021-02-07T19:11:21-05:00"
  22 + },
  23 + "/UF": {
  24 + "checksum": "2e10f186a4cdf5be438747f4bdc2d4d4",
  25 + "creationdate": "2021-02-07T19:11:21-05:00",
  26 + "mimetype": "text/plain",
  27 + "modificationdate": "2021-02-07T19:11:21-05:00"
  28 + }
  29 + }
11 }, 30 },
12 "att2": { 31 "att2": {
  32 + "description": null,
13 "filespec": "5 0 R", 33 "filespec": "5 0 R",
  34 + "names": {
  35 + "/F": "att2.txt",
  36 + "/UF": "att2.txt"
  37 + },
14 "preferredcontents": "10 0 R", 38 "preferredcontents": "10 0 R",
15 - "preferredname": "att2.txt" 39 + "preferredname": "att2.txt",
  40 + "streams": {
  41 + "/F": {
  42 + "checksum": "2fce9c8228e360ba9b04a1bd1bf63d6b",
  43 + "creationdate": null,
  44 + "mimetype": "text/plain",
  45 + "modificationdate": null
  46 + },
  47 + "/UF": {
  48 + "checksum": "2fce9c8228e360ba9b04a1bd1bf63d6b",
  49 + "creationdate": null,
  50 + "mimetype": "text/plain",
  51 + "modificationdate": null
  52 + }
  53 + }
16 }, 54 },
17 "att3": { 55 "att3": {
  56 + "description": null,
18 "filespec": "6 0 R", 57 "filespec": "6 0 R",
  58 + "names": {
  59 + "/F": "att3.txt",
  60 + "/UF": "π.txt"
  61 + },
19 "preferredcontents": "12 0 R", 62 "preferredcontents": "12 0 R",
20 - "preferredname": "π.txt" 63 + "preferredname": "π.txt",
  64 + "streams": {
  65 + "/F": {
  66 + "checksum": "2236c155b1d62b7f00285bba081d4336",
  67 + "creationdate": null,
  68 + "mimetype": "text/plain",
  69 + "modificationdate": null
  70 + },
  71 + "/UF": {
  72 + "checksum": "2236c155b1d62b7f00285bba081d4336",
  73 + "creationdate": null,
  74 + "mimetype": "text/plain",
  75 + "modificationdate": null
  76 + }
  77 + }
21 } 78 }
22 } 79 }
23 } 80 }
qpdf/qtest/qpdf/test76-list-verbose.out
@@ -6,7 +6,15 @@ att1 -&gt; 8,0 @@ -6,7 +6,15 @@ att1 -&gt; 8,0
6 /UF -> att1.txt 6 /UF -> att1.txt
7 all data streams: 7 all data streams:
8 /F -> 8,0 8 /F -> 8,0
  9 + creation date: D:20210207191121-05'00'
  10 + modification date: D:20210208001122Z
  11 + mime type: text/plain
  12 + checksum: 2e10f186a4cdf5be438747f4bdc2d4d4
9 /UF -> 8,0 13 /UF -> 8,0
  14 + creation date: D:20210207191121-05'00'
  15 + modification date: D:20210208001122Z
  16 + mime type: text/plain
  17 + checksum: 2e10f186a4cdf5be438747f4bdc2d4d4
10 att2 -> 10,0 18 att2 -> 10,0
11 preferred name: att2.txt 19 preferred name: att2.txt
12 all names: 20 all names:
@@ -14,7 +22,15 @@ att2 -&gt; 10,0 @@ -14,7 +22,15 @@ att2 -&gt; 10,0
14 /UF -> att2.txt 22 /UF -> att2.txt
15 all data streams: 23 all data streams:
16 /F -> 10,0 24 /F -> 10,0
  25 + creation date:
  26 + modification date:
  27 + mime type: text/plain
  28 + checksum: 2fce9c8228e360ba9b04a1bd1bf63d6b
17 /UF -> 10,0 29 /UF -> 10,0
  30 + creation date:
  31 + modification date:
  32 + mime type: text/plain
  33 + checksum: 2fce9c8228e360ba9b04a1bd1bf63d6b
18 att3 -> 12,0 34 att3 -> 12,0
19 preferred name: π.txt 35 preferred name: π.txt
20 all names: 36 all names:
@@ -22,4 +38,12 @@ att3 -&gt; 12,0 @@ -22,4 +38,12 @@ att3 -&gt; 12,0
22 /UF -> π.txt 38 /UF -> π.txt
23 all data streams: 39 all data streams:
24 /F -> 12,0 40 /F -> 12,0
  41 + creation date:
  42 + modification date:
  43 + mime type: text/plain
  44 + checksum: 2236c155b1d62b7f00285bba081d4336
25 /UF -> 12,0 45 /UF -> 12,0
  46 + creation date:
  47 + modification date:
  48 + mime type: text/plain
  49 + checksum: 2236c155b1d62b7f00285bba081d4336
qpdf/qtest/qpdf/utf16le-attachments.out
@@ -5,4 +5,12 @@ potato.png -&gt; 6,0 @@ -5,4 +5,12 @@ potato.png -&gt; 6,0
5 /UF -> π.png 5 /UF -> π.png
6 all data streams: 6 all data streams:
7 /F -> 6,0 7 /F -> 6,0
  8 + creation date: D:20220215153939-05'00'
  9 + modification date: D:20220215153939-05'00'
  10 + mime type:
  11 + checksum: c55e70c0c72d7eaf01230124fe5ff2d9
8 /UF -> 6,0 12 /UF -> 6,0
  13 + creation date: D:20220215153939-05'00'
  14 + modification date: D:20220215153939-05'00'
  15 + mime type:
  16 + checksum: c55e70c0c72d7eaf01230124fe5ff2d9
qtest/bin/qtest-driver
@@ -218,7 +218,7 @@ if (defined $tc_log) @@ -218,7 +218,7 @@ if (defined $tc_log)
218 print_xml(">\n"); 218 print_xml(">\n");
219 print_junit("<?xml version=\"1.0\"?>\n" . 219 print_junit("<?xml version=\"1.0\"?>\n" .
220 "<testsuites>\n"); 220 "<testsuites>\n");
221 -my @invalid_test_suites = (); 221 +my @failed_test_suites = ();
222 foreach my $test (@tests) 222 foreach my $test (@tests)
223 { 223 {
224 print_and_log("\nRunning $test\n"); 224 print_and_log("\nRunning $test\n");
@@ -228,7 +228,7 @@ foreach my $test (@tests) @@ -228,7 +228,7 @@ foreach my $test (@tests)
228 if (scalar(@results) != 5) 228 if (scalar(@results) != 5)
229 { 229 {
230 print_and_log("test driver $test returned invalid results\n"); 230 print_and_log("test driver $test returned invalid results\n");
231 - push(@invalid_test_suites, $test); 231 + push(@failed_test_suites, $test);
232 } 232 }
233 else 233 else
234 { 234 {
@@ -263,6 +263,10 @@ foreach my $test (@tests) @@ -263,6 +263,10 @@ foreach my $test (@tests)
263 263
264 my $passed = (($extra == 0) && ($missing == 0) && 264 my $passed = (($extra == 0) && ($missing == 0) &&
265 ($fails == 0) && ($xpasses == 0)); 265 ($fails == 0) && ($xpasses == 0));
  266 + if (! $passed)
  267 + {
  268 + push(@failed_test_suites, $test);
  269 + }
266 270
267 print_xml(" <testsummary\n" . 271 print_xml(" <testsummary\n" .
268 " overall-outcome=\"" .($passed ? 'pass' : 'fail') . "\"\n". 272 " overall-outcome=\"" .($passed ? 'pass' : 'fail') . "\"\n".
@@ -284,7 +288,7 @@ tc_do_final_checks(); @@ -284,7 +288,7 @@ tc_do_final_checks();
284 288
285 my $okay = ((($totpasses + $totxfails) == $tottests) && 289 my $okay = ((($totpasses + $totxfails) == $tottests) &&
286 ($errors == 0) && ($totmissing == 0) && ($totextra == 0) && 290 ($errors == 0) && ($totmissing == 0) && ($totextra == 0) &&
287 - ($coverage_okay) && (scalar(@invalid_test_suites) == 0)); 291 + ($coverage_okay) && (scalar(@failed_test_suites) == 0));
288 292
289 print "\n"; 293 print "\n";
290 print_and_pad("Overall test suite"); 294 print_and_pad("Overall test suite");
@@ -301,10 +305,10 @@ else @@ -301,10 +305,10 @@ else
301 } 305 }
302 306
303 my $summary = "\nTESTS COMPLETE. Summary:\n\n"; 307 my $summary = "\nTESTS COMPLETE. Summary:\n\n";
304 -if (@invalid_test_suites) 308 +if (@failed_test_suites)
305 { 309 {
306 - $summary .= "INVALID TEST SUITES:\n";  
307 - foreach my $t (@invalid_test_suites) 310 + $summary .= "FAILED TEST SUITES:\n";
  311 + foreach my $t (@failed_test_suites)
308 { 312 {
309 $summary .= " $t\n"; 313 $summary .= " $t\n";
310 } 314 }