aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-05-30 15:23:48 +0200
committerJay Berkenbilt <ejb@ql.org>2022-05-31 02:03:08 +0200
commitf049a77c5962a0e41723bc83900656ece821d916 (patch)
tree56f812a43074bfe2dfee658bbef014c094d2af1e
parent04fc7c4bea9b4efa38a7398b6db56a8fe5273bfb (diff)
downloadqpdf-f049a77c5962a0e41723bc83900656ece821d916.tar.zst
Add additional information when listing attachments
-rw-r--r--ChangeLog3
-rw-r--r--TODO3
-rw-r--r--job.sums2
-rw-r--r--libqpdf/QPDFJob.cc65
-rw-r--r--manual/cli.rst5
-rw-r--r--manual/release-notes.rst10
-rw-r--r--qpdf/qtest/attachments.test3
-rw-r--r--qpdf/qtest/json.test1
-rw-r--r--qpdf/qtest/qpdf/attachment-fields.pdf190
-rw-r--r--qpdf/qtest/qpdf/filter-attachment-date.pl8
-rw-r--r--qpdf/qtest/qpdf/json-attachment-fields-v1.out305
-rw-r--r--qpdf/qtest/qpdf/json-attachment-fields-v2.out241
-rw-r--r--qpdf/qtest/qpdf/list-attachments-1.out24
-rw-r--r--qpdf/qtest/qpdf/list-attachments-2.out48
-rw-r--r--qpdf/qtest/qpdf/list-attachments-3.out24
-rw-r--r--qpdf/qtest/qpdf/list-attachments-4.out8
-rw-r--r--qpdf/qtest/qpdf/test76-json.out63
-rw-r--r--qpdf/qtest/qpdf/test76-list-verbose.out24
-rw-r--r--qpdf/qtest/qpdf/utf16le-attachments.out8
-rwxr-xr-xqtest/bin/qtest-driver16
20 files changed, 1034 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index ea445e64..0d60467d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2022-05-30 Jay Berkenbilt <ejb@ql.org>
+ * Include additional information in --list-attachments --verbose
+ and in --json --json-key=attachments.
+
* Add QUtil::qpdf_time_to_iso8601 and QUtil::pdf_time_to_iso8601
for converting PDF/qpdf timestamps to ISO-8601 date format.
diff --git a/TODO b/TODO
index e66fb49b..663dbb40 100644
--- a/TODO
+++ b/TODO
@@ -72,9 +72,6 @@ Remaining work:
* --encryption: show recovered user password when available
- * --list-attachments: add information from --verbose. Add to a
- "details" subkey.
-
* Consider having --check, --show-encryption, etc., just select the
right keys when in json mode. I don't think I want check on by
default, so that might be different.
diff --git a/job.sums b/job.sums
index befae830..119c9bdf 100644
--- a/job.sums
+++ b/job.sums
@@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a947431
libqpdf/qpdf/auto_job_json_init.hh 5f6b53e3c81d4b54ce5c4cf9c3f52d0c02f987c53bf8841c0280367bad23e335
libqpdf/qpdf/auto_job_schema.hh 9d543cd4a43eafffc2c4b8a6fee29e399c271c52cb6f7d417ae5497b3c1127dc
manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
-manual/cli.rst e7c35f8183d015d7fe074e38baed4c89bad827fd9c23b4cafd73d562df82ab1b
+manual/cli.rst 82ead389c03bbf5e0498bd0571a11dc06544d591f4e4454c00322e3473fc556d
diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc
index 7c9e9bed..d7cc66cf 100644
--- a/libqpdf/QPDFJob.cc
+++ b/libqpdf/QPDFJob.cc
@@ -993,8 +993,16 @@ QPDFJob::doListAttachments(QPDF& pdf)
}
cout << " all data streams:" << std::endl;
for (auto i2: efoh->getEmbeddedFileStreams().ditems()) {
+ auto efs = QPDFEFStreamObjectHelper(i2.second);
cout << " " << i2.first << " -> "
- << i2.second.getObjGen() << std::endl;
+ << efs.getObjectHandle().getObjGen() << std::endl;
+ cout << " creation date: " << efs.getCreationDate()
+ << std::endl
+ << " modification date: " << efs.getModDate()
+ << std::endl
+ << " mime type: " << efs.getSubtype() << std::endl
+ << " checksum: "
+ << QUtil::hex_encode(efs.getChecksum()) << std::endl;
}
});
}
@@ -1445,6 +1453,22 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf)
void
QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf)
{
+ auto to_iso8601 = [](std::string const& d) {
+ // Convert PDF date to iso8601 if not empty; if empty, return
+ // empty.
+ std::string iso8601;
+ QUtil::pdf_time_to_iso8601(d, iso8601);
+ return iso8601;
+ };
+
+ auto null_or_string = [](std::string const& s) {
+ if (s.empty()) {
+ return JSON::makeNull();
+ } else {
+ return JSON::makeString(s);
+ }
+ };
+
JSON j_attachments = JSON::makeDictionary();
QPDFEmbeddedFileDocumentHelper efdh(pdf);
for (auto const& iter: efdh.getEmbeddedFiles()) {
@@ -1459,6 +1483,31 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf)
j_details.addDictionaryMember(
"preferredcontents",
JSON::makeString(fsoh->getEmbeddedFileStream().unparse()));
+ j_details.addDictionaryMember(
+ "description", null_or_string(fsoh->getDescription()));
+ auto j_names =
+ j_details.addDictionaryMember("names", JSON::makeDictionary());
+ for (auto const& i2: fsoh->getFilenames()) {
+ j_names.addDictionaryMember(i2.first, JSON::makeString(i2.second));
+ }
+ auto j_streams =
+ j_details.addDictionaryMember("streams", JSON::makeDictionary());
+ for (auto i2: fsoh->getEmbeddedFileStreams().ditems()) {
+ auto efs = QPDFEFStreamObjectHelper(i2.second);
+ auto j_stream =
+ j_streams.addDictionaryMember(i2.first, JSON::makeDictionary());
+ j_stream.addDictionaryMember(
+ "creationdate",
+ null_or_string(to_iso8601(efs.getCreationDate())));
+ j_stream.addDictionaryMember(
+ "modificationdate",
+ null_or_string(to_iso8601(efs.getCreationDate())));
+ j_stream.addDictionaryMember(
+ "mimetype", null_or_string(efs.getSubtype()));
+ j_stream.addDictionaryMember(
+ "checksum",
+ null_or_string(QUtil::hex_encode(efs.getChecksum())));
+ }
}
JSON::writeDictionaryItem(p, first, "attachments", j_attachments, 0);
}
@@ -1640,7 +1689,19 @@ QPDFJob::json_schema(int json_version, std::set<std::string>* keys)
"<attachment-key>": {
"filespec": "object containing the file spec",
"preferredcontents": "most preferred embedded file stream",
- "preferredname": "most preferred file name"
+ "preferredname": "most preferred file name",
+ "description": "description of attachment",
+ "names": {
+ "<name-key>": "file name for key"
+ },
+ "streams": {
+ "<stream-key>": {
+ "creationdate": "ISO-8601 creation date or null",
+ "modificationdate": "ISO-8601 modification date or null",
+ "mimetype": "mime type or null",
+ "checksum": "MD5 checksum or null"
+ }
+ }
}
})"));
}
diff --git a/manual/cli.rst b/manual/cli.rst
index c6e408c6..194bfacd 100644
--- a/manual/cli.rst
+++ b/manual/cli.rst
@@ -3124,7 +3124,10 @@ Related Options
:qpdf:ref:`--verbose`, additional information, including preferred
file name, description, dates, and more are also displayed. The key
is usually but not always equal to the file name and is needed by
- some of the other options. See also :ref:`attachments`.
+ some of the other options. See also :ref:`attachments`. Note that
+ this option displays dates in PDF timestamp syntax. When attachment
+ information is included in json output (see :ref:`--json`), dates
+ are shown in ISO-8601 format.
.. qpdf:option:: --show-attachment=key
diff --git a/manual/release-notes.rst b/manual/release-notes.rst
index 31ddabfd..d106ec11 100644
--- a/manual/release-notes.rst
+++ b/manual/release-notes.rst
@@ -96,6 +96,13 @@ For a detailed list of changes, please see the file
- See :ref:`breaking-crypto-api` for specific details, and see
:ref:`weak-crypto` for a general discussion.
+ - CLI Enhancements
+
+ - ``qpdf --list-attachments --verbose`` include some additional
+ information about attachments. Additional information about
+ attachments is also included in the ``attachments`` json key
+ with ``--json``.
+
- Library Enhancements
- New methods ``insertItemAndGet``, ``appendItemAndGet``,
@@ -120,6 +127,9 @@ For a detailed list of changes, please see the file
- Add new ``Pipeline`` type ``Pl_String`` to append to a
``std::string``.
+ - Add methods to QUtil for converting PDF timestamps and QPDFTime
+ objects to ISO-8601 timestamps.
+
- Enhance JSON class to better support incrementally reading and
writing large amounts of data without having to keep everything
in memory.
diff --git a/qpdf/qtest/attachments.test b/qpdf/qtest/attachments.test
index dbd47161..0d32ea0b 100644
--- a/qpdf/qtest/attachments.test
+++ b/qpdf/qtest/attachments.test
@@ -189,7 +189,8 @@ $td->runtest("add attachments: current date",
$td->NORMALIZE_NEWLINES);
$td->runtest("list attachments",
{$td->COMMAND =>
- "qpdf --password=u --list-attachments a.pdf --verbose"},
+ "qpdf --password=u --list-attachments a.pdf --verbose",
+ $td->FILTER => "perl filter-attachment-date.pl"},
{$td->FILE => "list-attachments-4.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
# The object to show here is the one in list-attachments-4.out
diff --git a/qpdf/qtest/json.test b/qpdf/qtest/json.test
index d010496b..1a2e1fe8 100644
--- a/qpdf/qtest/json.test
+++ b/qpdf/qtest/json.test
@@ -26,6 +26,7 @@ my @json_files = (
['field-types', ['--show-encryption-key']],
['image-streams', ['--decode-level=all']],
['image-streams', ['--decode-level=specialized']],
+ ['attachment-fields', []],
['page-labels-and-outlines', ['--json-key=objects']],
['page-labels-and-outlines', ['--json-key=pages']],
['page-labels-and-outlines', ['--json-key=pagelabels']],
diff --git a/qpdf/qtest/qpdf/attachment-fields.pdf b/qpdf/qtest/qpdf/attachment-fields.pdf
new file mode 100644
index 00000000..f48c8f76
--- /dev/null
+++ b/qpdf/qtest/qpdf/attachment-fields.pdf
@@ -0,0 +1,190 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+%% Original object ID: 1 0
+1 0 obj
+<<
+ /Names <<
+ /EmbeddedFiles 2 0 R
+ >>
+ /PageMode /UseAttachments
+ /Pages 3 0 R
+ /Type /Catalog
+>>
+endobj
+
+%% Original object ID: 2 0
+2 0 obj
+<<
+ /Names [
+ (a.txt)
+ 4 0 R
+ <feff03c0002e007400780074>
+ 5 0 R
+ ]
+>>
+endobj
+
+%% Original object ID: 3 0
+3 0 obj
+<<
+ /Count 1
+ /Kids [
+ 6 0 R
+ ]
+ /Type /Pages
+>>
+endobj
+
+%% Original object ID: 4 0
+4 0 obj
+<<
+ /EF <<
+ /F 7 0 R
+ /UF 7 0 R
+ >>
+ /F (a.txt)
+ /Type /Filespec
+ /UF (a.txt)
+>>
+endobj
+
+%% Original object ID: 5 0
+5 0 obj
+<<
+ /Desc (Two filenames)
+ /EF <<
+ /F 9 0 R
+ /UF 9 0 R
+ >>
+ /F (pi.txt)
+ /Type /Filespec
+ /UF <feff03c0002e007400780074>
+>>
+endobj
+
+%% Page 1
+%% Original object ID: 6 0
+6 0 obj
+<<
+ /Contents 11 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 3 0 R
+ /Resources <<
+ /Font <<
+ /F1 13 0 R
+ >>
+ /ProcSet 14 0 R
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Original object ID: 7 0
+7 0 obj
+<<
+ /Params <<
+ /Size 7
+ >>
+ /Type /EmbeddedFile
+ /Length 8 0 R
+>>
+stream
+potato
+endstream
+endobj
+
+8 0 obj
+7
+endobj
+
+%% Original object ID: 8 0
+9 0 obj
+<<
+ /Params <<
+ /CheckSum <e561f9248d7563d15dd93457b02ebbb6>
+ /CreationDate (D:20220530094116-05'00')
+ /ModDate (D:20220530094116-05'00')
+ /Size 7
+ >>
+ /Subtype /text#2fplain
+ /Type /EmbeddedFile
+ /Length 10 0 R
+>>
+stream
+potato
+endstream
+endobj
+
+10 0 obj
+7
+endobj
+
+%% Contents for page 1
+%% Original object ID: 9 0
+11 0 obj
+<<
+ /Length 12 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+
+12 0 obj
+44
+endobj
+
+%% Original object ID: 10 0
+13 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+%% Original object ID: 11 0
+14 0 obj
+[
+ /PDF
+ /Text
+]
+endobj
+
+xref
+0 15
+0000000000 65535 f
+0000000052 00000 n
+0000000203 00000 n
+0000000330 00000 n
+0000000429 00000 n
+0000000564 00000 n
+0000000753 00000 n
+0000000975 00000 n
+0000001089 00000 n
+0000001134 00000 n
+0000001406 00000 n
+0000001475 00000 n
+0000001576 00000 n
+0000001624 00000 n
+0000001759 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 15
+ /ID [<3d1a89e08f9d6b3e1f787d04fceed440><4e13de38230bb10a03e49285a742c392>]
+>>
+startxref
+1795
+%%EOF
diff --git a/qpdf/qtest/qpdf/filter-attachment-date.pl b/qpdf/qtest/qpdf/filter-attachment-date.pl
new file mode 100644
index 00000000..6def1b99
--- /dev/null
+++ b/qpdf/qtest/qpdf/filter-attachment-date.pl
@@ -0,0 +1,8 @@
+use warnings;
+use strict;
+
+while (<>)
+{
+ s/D:\d{14}\S+/<date>/;
+ print;
+}
diff --git a/qpdf/qtest/qpdf/json-attachment-fields-v1.out b/qpdf/qtest/qpdf/json-attachment-fields-v1.out
new file mode 100644
index 00000000..21fe88be
--- /dev/null
+++ b/qpdf/qtest/qpdf/json-attachment-fields-v1.out
@@ -0,0 +1,305 @@
+{
+ "version": 1,
+ "parameters": {
+ "decodelevel": "generalized"
+ },
+ "pages": [
+ {
+ "contents": [
+ "11 0 R"
+ ],
+ "images": [],
+ "label": null,
+ "object": "6 0 R",
+ "outlines": [],
+ "pageposfrom1": 1
+ }
+ ],
+ "pagelabels": [],
+ "acroform": {
+ "fields": [],
+ "hasacroform": false,
+ "needappearances": false
+ },
+ "attachments": {
+ "a.txt": {
+ "description": null,
+ "filespec": "4 0 R",
+ "names": {
+ "/F": "a.txt",
+ "/UF": "a.txt"
+ },
+ "preferredcontents": "7 0 R",
+ "preferredname": "a.txt",
+ "streams": {
+ "/F": {
+ "checksum": null,
+ "creationdate": null,
+ "mimetype": null,
+ "modificationdate": null
+ },
+ "/UF": {
+ "checksum": null,
+ "creationdate": null,
+ "mimetype": null,
+ "modificationdate": null
+ }
+ }
+ },
+ "Ï€.txt": {
+ "description": "Two filenames",
+ "filespec": "5 0 R",
+ "names": {
+ "/F": "pi.txt",
+ "/UF": "Ï€.txt"
+ },
+ "preferredcontents": "9 0 R",
+ "preferredname": "Ï€.txt",
+ "streams": {
+ "/F": {
+ "checksum": "e561f9248d7563d15dd93457b02ebbb6",
+ "creationdate": "2022-05-30T09:41:16-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2022-05-30T09:41:16-05:00"
+ },
+ "/UF": {
+ "checksum": "e561f9248d7563d15dd93457b02ebbb6",
+ "creationdate": "2022-05-30T09:41:16-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2022-05-30T09:41:16-05:00"
+ }
+ }
+ }
+ },
+ "encrypt": {
+ "capabilities": {
+ "accessibility": true,
+ "extract": true,
+ "moddifyannotations": true,
+ "modify": true,
+ "modifyassembly": true,
+ "modifyforms": true,
+ "modifyother": true,
+ "printhigh": true,
+ "printlow": true
+ },
+ "encrypted": false,
+ "ownerpasswordmatched": false,
+ "parameters": {
+ "P": 0,
+ "R": 0,
+ "V": 0,
+ "bits": 0,
+ "filemethod": "none",
+ "key": null,
+ "method": "none",
+ "streammethod": "none",
+ "stringmethod": "none"
+ },
+ "userpasswordmatched": false
+ },
+ "outlines": [],
+ "objects": {
+ "1 0 R": {
+ "/Names": {
+ "/EmbeddedFiles": "2 0 R"
+ },
+ "/PageMode": "/UseAttachments",
+ "/Pages": "3 0 R",
+ "/Type": "/Catalog"
+ },
+ "2 0 R": {
+ "/Names": [
+ "a.txt",
+ "4 0 R",
+ "Ï€.txt",
+ "5 0 R"
+ ]
+ },
+ "3 0 R": {
+ "/Count": 1,
+ "/Kids": [
+ "6 0 R"
+ ],
+ "/Type": "/Pages"
+ },
+ "4 0 R": {
+ "/EF": {
+ "/F": "7 0 R",
+ "/UF": "7 0 R"
+ },
+ "/F": "a.txt",
+ "/Type": "/Filespec",
+ "/UF": "a.txt"
+ },
+ "5 0 R": {
+ "/Desc": "Two filenames",
+ "/EF": {
+ "/F": "9 0 R",
+ "/UF": "9 0 R"
+ },
+ "/F": "pi.txt",
+ "/Type": "/Filespec",
+ "/UF": "Ï€.txt"
+ },
+ "6 0 R": {
+ "/Contents": "11 0 R",
+ "/MediaBox": [
+ 0,
+ 0,
+ 612,
+ 792
+ ],
+ "/Parent": "3 0 R",
+ "/Resources": {
+ "/Font": {
+ "/F1": "13 0 R"
+ },
+ "/ProcSet": "14 0 R"
+ },
+ "/Type": "/Page"
+ },
+ "7 0 R": {
+ "/Length": "8 0 R",
+ "/Params": {
+ "/Size": 7
+ },
+ "/Type": "/EmbeddedFile"
+ },
+ "8 0 R": 7,
+ "9 0 R": {
+ "/Length": "10 0 R",
+ "/Params": {
+ "/CheckSum": "åaù$“ucÑ]Ù4W°.»¶",
+ "/CreationDate": "D:20220530094116-05'00'",
+ "/ModDate": "D:20220530094116-05'00'",
+ "/Size": 7
+ },
+ "/Subtype": "/text#2fplain",
+ "/Type": "/EmbeddedFile"
+ },
+ "10 0 R": 7,
+ "11 0 R": {
+ "/Length": "12 0 R"
+ },
+ "12 0 R": 44,
+ "13 0 R": {
+ "/BaseFont": "/Helvetica",
+ "/Encoding": "/WinAnsiEncoding",
+ "/Subtype": "/Type1",
+ "/Type": "/Font"
+ },
+ "14 0 R": [
+ "/PDF",
+ "/Text"
+ ],
+ "trailer": {
+ "/ID": [
+ "=ˆ›à‘šk>˜x}\u0004üîÔ@",
+ "N\u0013Þ8#\u000b±\n\u0003ä™–§BÙ"
+ ],
+ "/Root": "1 0 R",
+ "/Size": 15
+ }
+ },
+ "objectinfo": {
+ "1 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "2 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "3 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "4 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "5 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "6 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "7 0 R": {
+ "stream": {
+ "filter": null,
+ "is": true,
+ "length": 7
+ }
+ },
+ "8 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "9 0 R": {
+ "stream": {
+ "filter": null,
+ "is": true,
+ "length": 7
+ }
+ },
+ "10 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "11 0 R": {
+ "stream": {
+ "filter": null,
+ "is": true,
+ "length": 44
+ }
+ },
+ "12 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "13 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ },
+ "14 0 R": {
+ "stream": {
+ "filter": null,
+ "is": false,
+ "length": null
+ }
+ }
+ }
+}
diff --git a/qpdf/qtest/qpdf/json-attachment-fields-v2.out b/qpdf/qtest/qpdf/json-attachment-fields-v2.out
new file mode 100644
index 00000000..e94e05dc
--- /dev/null
+++ b/qpdf/qtest/qpdf/json-attachment-fields-v2.out
@@ -0,0 +1,241 @@
+{
+ "version": 2,
+ "parameters": {
+ "decodelevel": "generalized"
+ },
+ "pages": [
+ {
+ "contents": [
+ "11 0 R"
+ ],
+ "images": [],
+ "label": null,
+ "object": "6 0 R",
+ "outlines": [],
+ "pageposfrom1": 1
+ }
+ ],
+ "pagelabels": [],
+ "acroform": {
+ "fields": [],
+ "hasacroform": false,
+ "needappearances": false
+ },
+ "attachments": {
+ "a.txt": {
+ "description": null,
+ "filespec": "4 0 R",
+ "names": {
+ "/F": "a.txt",
+ "/UF": "a.txt"
+ },
+ "preferredcontents": "7 0 R",
+ "preferredname": "a.txt",
+ "streams": {
+ "/F": {
+ "checksum": null,
+ "creationdate": null,
+ "mimetype": null,
+ "modificationdate": null
+ },
+ "/UF": {
+ "checksum": null,
+ "creationdate": null,
+ "mimetype": null,
+ "modificationdate": null
+ }
+ }
+ },
+ "Ï€.txt": {
+ "description": "Two filenames",
+ "filespec": "5 0 R",
+ "names": {
+ "/F": "pi.txt",
+ "/UF": "Ï€.txt"
+ },
+ "preferredcontents": "9 0 R",
+ "preferredname": "Ï€.txt",
+ "streams": {
+ "/F": {
+ "checksum": "e561f9248d7563d15dd93457b02ebbb6",
+ "creationdate": "2022-05-30T09:41:16-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2022-05-30T09:41:16-05:00"
+ },
+ "/UF": {
+ "checksum": "e561f9248d7563d15dd93457b02ebbb6",
+ "creationdate": "2022-05-30T09:41:16-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2022-05-30T09:41:16-05:00"
+ }
+ }
+ }
+ },
+ "encrypt": {
+ "capabilities": {
+ "accessibility": true,
+ "extract": true,
+ "modify": true,
+ "modifyannotations": true,
+ "modifyassembly": true,
+ "modifyforms": true,
+ "modifyother": true,
+ "printhigh": true,
+ "printlow": true
+ },
+ "encrypted": false,
+ "ownerpasswordmatched": false,
+ "parameters": {
+ "P": 0,
+ "R": 0,
+ "V": 0,
+ "bits": 0,
+ "filemethod": "none",
+ "key": null,
+ "method": "none",
+ "streammethod": "none",
+ "stringmethod": "none"
+ },
+ "userpasswordmatched": false
+ },
+ "outlines": [],
+ "objects": {
+ "obj:1 0 R": {
+ "value": {
+ "/Names": {
+ "/EmbeddedFiles": "2 0 R"
+ },
+ "/PageMode": "/UseAttachments",
+ "/Pages": "3 0 R",
+ "/Type": "/Catalog"
+ }
+ },
+ "obj:2 0 R": {
+ "value": {
+ "/Names": [
+ "u:a.txt",
+ "4 0 R",
+ "u:Ï€.txt",
+ "5 0 R"
+ ]
+ }
+ },
+ "obj:3 0 R": {
+ "value": {
+ "/Count": 1,
+ "/Kids": [
+ "6 0 R"
+ ],
+ "/Type": "/Pages"
+ }
+ },
+ "obj:4 0 R": {
+ "value": {
+ "/EF": {
+ "/F": "7 0 R",
+ "/UF": "7 0 R"
+ },
+ "/F": "u:a.txt",
+ "/Type": "/Filespec",
+ "/UF": "u:a.txt"
+ }
+ },
+ "obj:5 0 R": {
+ "value": {
+ "/Desc": "u:Two filenames",
+ "/EF": {
+ "/F": "9 0 R",
+ "/UF": "9 0 R"
+ },
+ "/F": "u:pi.txt",
+ "/Type": "/Filespec",
+ "/UF": "u:Ï€.txt"
+ }
+ },
+ "obj:6 0 R": {
+ "value": {
+ "/Contents": "11 0 R",
+ "/MediaBox": [
+ 0,
+ 0,
+ 612,
+ 792
+ ],
+ "/Parent": "3 0 R",
+ "/Resources": {
+ "/Font": {
+ "/F1": "13 0 R"
+ },
+ "/ProcSet": "14 0 R"
+ },
+ "/Type": "/Page"
+ }
+ },
+ "obj:7 0 R": {
+ "stream": {
+ "dict": {
+ "/Length": "8 0 R",
+ "/Params": {
+ "/Size": 7
+ },
+ "/Type": "/EmbeddedFile"
+ }
+ }
+ },
+ "obj:8 0 R": {
+ "value": 7
+ },
+ "obj:9 0 R": {
+ "stream": {
+ "dict": {
+ "/Length": "10 0 R",
+ "/Params": {
+ "/CheckSum": "b:e561f9248d7563d15dd93457b02ebbb6",
+ "/CreationDate": "u:D:20220530094116-05'00'",
+ "/ModDate": "u:D:20220530094116-05'00'",
+ "/Size": 7
+ },
+ "/Subtype": "/text/plain",
+ "/Type": "/EmbeddedFile"
+ }
+ }
+ },
+ "obj:10 0 R": {
+ "value": 7
+ },
+ "obj:11 0 R": {
+ "stream": {
+ "dict": {
+ "/Length": "12 0 R"
+ }
+ }
+ },
+ "obj:12 0 R": {
+ "value": 44
+ },
+ "obj:13 0 R": {
+ "value": {
+ "/BaseFont": "/Helvetica",
+ "/Encoding": "/WinAnsiEncoding",
+ "/Subtype": "/Type1",
+ "/Type": "/Font"
+ }
+ },
+ "obj:14 0 R": {
+ "value": [
+ "/PDF",
+ "/Text"
+ ]
+ },
+ "trailer": {
+ "value": {
+ "/ID": [
+ "b:3d1a89e08f9d6b3e1f787d04fceed440",
+ "b:4e13de38230bb10a03e49285a742c392"
+ ],
+ "/Root": "1 0 R",
+ "/Size": 15
+ }
+ }
+ }
+}
diff --git a/qpdf/qtest/qpdf/list-attachments-1.out b/qpdf/qtest/qpdf/list-attachments-1.out
index 6e94cc64..5fac5ea2 100644
--- a/qpdf/qtest/qpdf/list-attachments-1.out
+++ b/qpdf/qtest/qpdf/list-attachments-1.out
@@ -5,7 +5,15 @@ auto-1 -> 8,0
/UF -> auto-1
all data streams:
/F -> 8,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
/UF -> 8,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
auto-3 -> 10,0
description: two words
preferred name: auto-Three.txt
@@ -14,7 +22,15 @@ auto-3 -> 10,0
/UF -> auto-Three.txt
all data streams:
/F -> 10,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
/UF -> 10,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
auto-Two -> 12,0
preferred name: auto-2
all names:
@@ -22,4 +38,12 @@ auto-Two -> 12,0
/UF -> auto-2
all data streams:
/F -> 12,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
/UF -> 12,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
diff --git a/qpdf/qtest/qpdf/list-attachments-2.out b/qpdf/qtest/qpdf/list-attachments-2.out
index d5488020..1683aef2 100644
--- a/qpdf/qtest/qpdf/list-attachments-2.out
+++ b/qpdf/qtest/qpdf/list-attachments-2.out
@@ -5,7 +5,15 @@
/UF -> auto-1
all data streams:
/F -> 11,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
/UF -> 11,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
1-auto-3 -> 13,0
description: two words
preferred name: auto-Three.txt
@@ -14,7 +22,15 @@
/UF -> auto-Three.txt
all data streams:
/F -> 13,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
/UF -> 13,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
1-auto-Two -> 15,0
preferred name: auto-2
all names:
@@ -22,7 +38,15 @@
/UF -> auto-2
all data streams:
/F -> 15,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
/UF -> 15,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
auto-1 -> 17,0
preferred name: auto-1
all names:
@@ -30,7 +54,15 @@ auto-1 -> 17,0
/UF -> auto-1
all data streams:
/F -> 17,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
/UF -> 17,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type: text/plain
+ checksum: a857d18d3fc23ad412122ef040733331
auto-3 -> 19,0
description: two words
preferred name: auto-Three.txt
@@ -39,7 +71,15 @@ auto-3 -> 19,0
/UF -> auto-Three.txt
all data streams:
/F -> 19,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
/UF -> 19,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
auto-Two -> 21,0
preferred name: auto-2
all names:
@@ -47,4 +87,12 @@ auto-Two -> 21,0
/UF -> auto-2
all data streams:
/F -> 21,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
/UF -> 21,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
diff --git a/qpdf/qtest/qpdf/list-attachments-3.out b/qpdf/qtest/qpdf/list-attachments-3.out
index 0467b59d..e48bb4c0 100644
--- a/qpdf/qtest/qpdf/list-attachments-3.out
+++ b/qpdf/qtest/qpdf/list-attachments-3.out
@@ -5,7 +5,15 @@ auto-1 -> 8,0
/UF -> auto-2
all data streams:
/F -> 8,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
/UF -> 8,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
auto-3 -> 10,0
description: two words
preferred name: auto-Three.txt
@@ -14,7 +22,15 @@ auto-3 -> 10,0
/UF -> auto-Three.txt
all data streams:
/F -> 10,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
/UF -> 10,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: d6c7ac7cf295ae133fea186cfd068dab
auto-Two -> 12,0
preferred name: auto-2
all names:
@@ -22,4 +38,12 @@ auto-Two -> 12,0
/UF -> auto-2
all data streams:
/F -> 12,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
/UF -> 12,0
+ creation date: D:20210210091359-05'00'
+ modification date: D:20210210141359Z
+ mime type:
+ checksum: 9f991a5669c47a94f9350f53e3953e57
diff --git a/qpdf/qtest/qpdf/list-attachments-4.out b/qpdf/qtest/qpdf/list-attachments-4.out
index b2d59e08..304b1e3d 100644
--- a/qpdf/qtest/qpdf/list-attachments-4.out
+++ b/qpdf/qtest/qpdf/list-attachments-4.out
@@ -5,4 +5,12 @@ auto-1 -> 6,0
/UF -> auto-1
all data streams:
/F -> 6,0
+ creation date: <date>
+ modification date: <date>
+ mime type:
+ checksum: a857d18d3fc23ad412122ef040733331
/UF -> 6,0
+ creation date: <date>
+ modification date: <date>
+ mime type:
+ checksum: a857d18d3fc23ad412122ef040733331
diff --git a/qpdf/qtest/qpdf/test76-json.out b/qpdf/qtest/qpdf/test76-json.out
index 02f0317c..df326e83 100644
--- a/qpdf/qtest/qpdf/test76-json.out
+++ b/qpdf/qtest/qpdf/test76-json.out
@@ -5,19 +5,76 @@
},
"attachments": {
"att1": {
+ "description": "some text",
"filespec": "4 0 R",
+ "names": {
+ "/F": "att1.txt",
+ "/UF": "att1.txt"
+ },
"preferredcontents": "8 0 R",
- "preferredname": "att1.txt"
+ "preferredname": "att1.txt",
+ "streams": {
+ "/F": {
+ "checksum": "2e10f186a4cdf5be438747f4bdc2d4d4",
+ "creationdate": "2021-02-07T19:11:21-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2021-02-07T19:11:21-05:00"
+ },
+ "/UF": {
+ "checksum": "2e10f186a4cdf5be438747f4bdc2d4d4",
+ "creationdate": "2021-02-07T19:11:21-05:00",
+ "mimetype": "text/plain",
+ "modificationdate": "2021-02-07T19:11:21-05:00"
+ }
+ }
},
"att2": {
+ "description": null,
"filespec": "5 0 R",
+ "names": {
+ "/F": "att2.txt",
+ "/UF": "att2.txt"
+ },
"preferredcontents": "10 0 R",
- "preferredname": "att2.txt"
+ "preferredname": "att2.txt",
+ "streams": {
+ "/F": {
+ "checksum": "2fce9c8228e360ba9b04a1bd1bf63d6b",
+ "creationdate": null,
+ "mimetype": "text/plain",
+ "modificationdate": null
+ },
+ "/UF": {
+ "checksum": "2fce9c8228e360ba9b04a1bd1bf63d6b",
+ "creationdate": null,
+ "mimetype": "text/plain",
+ "modificationdate": null
+ }
+ }
},
"att3": {
+ "description": null,
"filespec": "6 0 R",
+ "names": {
+ "/F": "att3.txt",
+ "/UF": "Ï€.txt"
+ },
"preferredcontents": "12 0 R",
- "preferredname": "Ï€.txt"
+ "preferredname": "Ï€.txt",
+ "streams": {
+ "/F": {
+ "checksum": "2236c155b1d62b7f00285bba081d4336",
+ "creationdate": null,
+ "mimetype": "text/plain",
+ "modificationdate": null
+ },
+ "/UF": {
+ "checksum": "2236c155b1d62b7f00285bba081d4336",
+ "creationdate": null,
+ "mimetype": "text/plain",
+ "modificationdate": null
+ }
+ }
}
}
}
diff --git a/qpdf/qtest/qpdf/test76-list-verbose.out b/qpdf/qtest/qpdf/test76-list-verbose.out
index 5e6df1a2..c64e1f02 100644
--- a/qpdf/qtest/qpdf/test76-list-verbose.out
+++ b/qpdf/qtest/qpdf/test76-list-verbose.out
@@ -6,7 +6,15 @@ att1 -> 8,0
/UF -> att1.txt
all data streams:
/F -> 8,0
+ creation date: D:20210207191121-05'00'
+ modification date: D:20210208001122Z
+ mime type: text/plain
+ checksum: 2e10f186a4cdf5be438747f4bdc2d4d4
/UF -> 8,0
+ creation date: D:20210207191121-05'00'
+ modification date: D:20210208001122Z
+ mime type: text/plain
+ checksum: 2e10f186a4cdf5be438747f4bdc2d4d4
att2 -> 10,0
preferred name: att2.txt
all names:
@@ -14,7 +22,15 @@ att2 -> 10,0
/UF -> att2.txt
all data streams:
/F -> 10,0
+ creation date:
+ modification date:
+ mime type: text/plain
+ checksum: 2fce9c8228e360ba9b04a1bd1bf63d6b
/UF -> 10,0
+ creation date:
+ modification date:
+ mime type: text/plain
+ checksum: 2fce9c8228e360ba9b04a1bd1bf63d6b
att3 -> 12,0
preferred name: π.txt
all names:
@@ -22,4 +38,12 @@ att3 -> 12,0
/UF -> π.txt
all data streams:
/F -> 12,0
+ creation date:
+ modification date:
+ mime type: text/plain
+ checksum: 2236c155b1d62b7f00285bba081d4336
/UF -> 12,0
+ creation date:
+ modification date:
+ mime type: text/plain
+ checksum: 2236c155b1d62b7f00285bba081d4336
diff --git a/qpdf/qtest/qpdf/utf16le-attachments.out b/qpdf/qtest/qpdf/utf16le-attachments.out
index 74abc20b..f4a409e1 100644
--- a/qpdf/qtest/qpdf/utf16le-attachments.out
+++ b/qpdf/qtest/qpdf/utf16le-attachments.out
@@ -5,4 +5,12 @@ potato.png -> 6,0
/UF -> π.png
all data streams:
/F -> 6,0
+ creation date: D:20220215153939-05'00'
+ modification date: D:20220215153939-05'00'
+ mime type:
+ checksum: c55e70c0c72d7eaf01230124fe5ff2d9
/UF -> 6,0
+ creation date: D:20220215153939-05'00'
+ modification date: D:20220215153939-05'00'
+ mime type:
+ checksum: c55e70c0c72d7eaf01230124fe5ff2d9
diff --git a/qtest/bin/qtest-driver b/qtest/bin/qtest-driver
index ce08f29f..c37c4d1d 100755
--- a/qtest/bin/qtest-driver
+++ b/qtest/bin/qtest-driver
@@ -218,7 +218,7 @@ if (defined $tc_log)
print_xml(">\n");
print_junit("<?xml version=\"1.0\"?>\n" .
"<testsuites>\n");
-my @invalid_test_suites = ();
+my @failed_test_suites = ();
foreach my $test (@tests)
{
print_and_log("\nRunning $test\n");
@@ -228,7 +228,7 @@ foreach my $test (@tests)
if (scalar(@results) != 5)
{
print_and_log("test driver $test returned invalid results\n");
- push(@invalid_test_suites, $test);
+ push(@failed_test_suites, $test);
}
else
{
@@ -263,6 +263,10 @@ foreach my $test (@tests)
my $passed = (($extra == 0) && ($missing == 0) &&
($fails == 0) && ($xpasses == 0));
+ if (! $passed)
+ {
+ push(@failed_test_suites, $test);
+ }
print_xml(" <testsummary\n" .
" overall-outcome=\"" .($passed ? 'pass' : 'fail') . "\"\n".
@@ -284,7 +288,7 @@ tc_do_final_checks();
my $okay = ((($totpasses + $totxfails) == $tottests) &&
($errors == 0) && ($totmissing == 0) && ($totextra == 0) &&
- ($coverage_okay) && (scalar(@invalid_test_suites) == 0));
+ ($coverage_okay) && (scalar(@failed_test_suites) == 0));
print "\n";
print_and_pad("Overall test suite");
@@ -301,10 +305,10 @@ else
}
my $summary = "\nTESTS COMPLETE. Summary:\n\n";
-if (@invalid_test_suites)
+if (@failed_test_suites)
{
- $summary .= "INVALID TEST SUITES:\n";
- foreach my $t (@invalid_test_suites)
+ $summary .= "FAILED TEST SUITES:\n";
+ foreach my $t (@failed_test_suites)
{
$summary .= " $t\n";
}