summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2021-02-10 21:35:01 +0100
committerJay Berkenbilt <ejb@ql.org>2021-02-10 21:46:18 +0100
commitaccb891b4f785b94ad9d2a6d415d9987a13747c9 (patch)
tree055932cdab7c631112bc246a76c63ebcfb0c51f7
parent832d792e4e88b85f4926e1241870de4d6ec2d772 (diff)
downloadqpdf-accb891b4f785b94ad9d2a6d415d9987a13747c9.tar.zst
Add attachment information to the json output
-rw-r--r--ChangeLog3
-rw-r--r--manual/qpdf-manual.xml13
-rw-r--r--qpdf/qpdf.cc44
-rw-r--r--qpdf/qtest/qpdf.test6
-rw-r--r--qpdf/qtest/qpdf/direct-pages-json.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types---show-encryption-key.out1
-rw-r--r--qpdf/qtest/qpdf/json-field-types.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-all.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-small.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams-specialized.out1
-rw-r--r--qpdf/qtest/qpdf/json-image-streams.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-actions.out1
-rw-r--r--qpdf/qtest/qpdf/json-outlines-with-old-root-dests.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-and-outlines.out1
-rw-r--r--qpdf/qtest/qpdf/json-page-labels-num-tree.out1
-rw-r--r--qpdf/qtest/qpdf/page_api_2-json.out1
-rw-r--r--qpdf/qtest/qpdf/test76-json.out23
17 files changed, 99 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index be8d2564..f587b967 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2021-02-10 Jay Berkenbilt <ejb@ql.org>
+ * Add "attachments" as an additional json key, and add some
+ information about attachments to the json output.
+
* Add new command-line arguments for operating on attachments:
--list-attachments, --add-attachment, --remove-attachment,
--copy-attachments-from. See --help and manual for details.
diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml
index 5205028d..6885aff6 100644
--- a/manual/qpdf-manual.xml
+++ b/manual/qpdf-manual.xml
@@ -5104,6 +5104,19 @@ print "\n";
than using <option>@file</option> for this purpose.
</para>
</listitem>
+ <listitem>
+ <para>
+ Add some information about attachments to the json output,
+ and added <literal>attachments</literal> as an additional
+ json key. The information included here is limited to the
+ preferred name and content stream and a reference to the
+ file spec object. This is enough detail for clients to avoid
+ the hassle of navigating a name tree and provides what is
+ needed for basic enumeration and extraction of attachments.
+ More detailed information can be obtained by following the
+ reference to the file spec object.
+ </para>
+ </listitem>
</itemizedlist>
</listitem>
<listitem>
diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc
index d23fad09..e41be64b 100644
--- a/qpdf/qpdf.cc
+++ b/qpdf/qpdf.cc
@@ -699,6 +699,22 @@ static JSON json_schema(std::set<std::string>* keys = 0)
"filemethod",
JSON::makeString("encryption method for attachments"));
}
+ if (all_keys || keys->count("attachments"))
+ {
+ JSON attachments = schema.addDictionaryMember(
+ "attachments", JSON::makeDictionary());
+ JSON details = attachments.addDictionaryMember(
+ "<attachment-key>", JSON::makeDictionary());
+ details.addDictionaryMember(
+ "filespec",
+ JSON::makeString("object containing the file spec"));
+ details.addDictionaryMember(
+ "preferredname",
+ JSON::makeString("most preferred file name"));
+ details.addDictionaryMember(
+ "preferredcontents",
+ JSON::makeString("most preferred embedded file stream"));
+ }
return schema;
}
@@ -1114,7 +1130,7 @@ ArgParser::initOptionTable()
// places: json_schema, do_json, and initOptionTable.
char const* json_key_choices[] = {
"objects", "objectinfo", "pages", "pagelabels", "outlines",
- "acroform", "encrypt", 0};
+ "acroform", "encrypt", "attachments", 0};
(*t)["json-key"] = oe_requiredChoices(
&ArgParser::argJsonKey, json_key_choices);
(*t)["json-object"] = oe_requiredParameter(
@@ -4568,6 +4584,28 @@ static void do_json_encrypt(QPDF& pdf, Options& o, JSON& j)
"filemethod", JSON::makeString(s_file_method));
}
+static void do_json_attachments(QPDF& pdf, Options& o, JSON& j)
+{
+ JSON j_attachments = j.addDictionaryMember(
+ "attachments", JSON::makeDictionary());
+ QPDFEmbeddedFileDocumentHelper efdh(pdf);
+ for (auto const& iter: efdh.getEmbeddedFiles())
+ {
+ std::string const& key = iter.first;
+ auto fsoh = iter.second;
+ auto j_details = j_attachments.addDictionaryMember(
+ key, JSON::makeDictionary());
+ j_details.addDictionaryMember(
+ "filespec",
+ JSON::makeString(fsoh->getObjectHandle().unparse()));
+ j_details.addDictionaryMember(
+ "preferredname", JSON::makeString(fsoh->getFilename()));
+ j_details.addDictionaryMember(
+ "preferredcontents",
+ JSON::makeString(fsoh->getEmbeddedFileStream().unparse()));
+ }
+}
+
static void do_json(QPDF& pdf, Options& o)
{
JSON j = JSON::makeDictionary();
@@ -4628,6 +4666,10 @@ static void do_json(QPDF& pdf, Options& o)
{
do_json_encrypt(pdf, o, j);
}
+ if (all_keys || o.json_keys.count("attachments"))
+ {
+ do_json_attachments(pdf, o, j);
+ }
// Check against schema
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 348d3948..dba10181 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -523,7 +523,7 @@ $td->runtest("page operations on form xobject",
show_ntests();
# ----------
$td->notify("--- File Attachments ---");
-$n_tests += 33;
+$n_tests += 34;
open(F, ">auto-txt") or die;
print F "from file";
@@ -547,6 +547,10 @@ $td->runtest("list attachments verbose",
{$td->COMMAND => "qpdf --list-attachments --verbose a.pdf"},
{$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("attachments json",
+ {$td->COMMAND => "qpdf --json --json-key=attachments a.pdf"},
+ {$td->FILE => "test76-json.out", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
$td->runtest("remove attachment (test_driver)",
{$td->COMMAND => "test_driver 77 test76.pdf"},
{$td->STRING => "test 77 done\n", $td->EXIT_STATUS => 0},
diff --git a/qpdf/qtest/qpdf/direct-pages-json.out b/qpdf/qtest/qpdf/direct-pages-json.out
index 0bd43563..52e5e2dd 100644
--- a/qpdf/qtest/qpdf/direct-pages-json.out
+++ b/qpdf/qtest/qpdf/direct-pages-json.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-field-types---show-encryption-key.out b/qpdf/qtest/qpdf/json-field-types---show-encryption-key.out
index 7bc40bdb..ad9c2003 100644
--- a/qpdf/qtest/qpdf/json-field-types---show-encryption-key.out
+++ b/qpdf/qtest/qpdf/json-field-types---show-encryption-key.out
@@ -385,6 +385,7 @@
"hasacroform": true,
"needappearances": true
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-field-types.out b/qpdf/qtest/qpdf/json-field-types.out
index 7bc40bdb..ad9c2003 100644
--- a/qpdf/qtest/qpdf/json-field-types.out
+++ b/qpdf/qtest/qpdf/json-field-types.out
@@ -385,6 +385,7 @@
"hasacroform": true,
"needappearances": true
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-image-streams-all.out b/qpdf/qtest/qpdf/json-image-streams-all.out
index 8eaa4583..3dea8852 100644
--- a/qpdf/qtest/qpdf/json-image-streams-all.out
+++ b/qpdf/qtest/qpdf/json-image-streams-all.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-image-streams-small.out b/qpdf/qtest/qpdf/json-image-streams-small.out
index dd7935ee..92d0c4f3 100644
--- a/qpdf/qtest/qpdf/json-image-streams-small.out
+++ b/qpdf/qtest/qpdf/json-image-streams-small.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-image-streams-specialized.out b/qpdf/qtest/qpdf/json-image-streams-specialized.out
index 9c6567f5..c342f9e6 100644
--- a/qpdf/qtest/qpdf/json-image-streams-specialized.out
+++ b/qpdf/qtest/qpdf/json-image-streams-specialized.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-image-streams.out b/qpdf/qtest/qpdf/json-image-streams.out
index 734868a5..2cfbd531 100644
--- a/qpdf/qtest/qpdf/json-image-streams.out
+++ b/qpdf/qtest/qpdf/json-image-streams.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-outlines-with-actions.out b/qpdf/qtest/qpdf/json-outlines-with-actions.out
index 25776abe..9755d0b8 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-actions.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-actions.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests.out b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests.out
index 11735197..af3ce99c 100644
--- a/qpdf/qtest/qpdf/json-outlines-with-old-root-dests.out
+++ b/qpdf/qtest/qpdf/json-outlines-with-old-root-dests.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-page-labels-and-outlines.out b/qpdf/qtest/qpdf/json-page-labels-and-outlines.out
index b0de1c1d..e7d702f6 100644
--- a/qpdf/qtest/qpdf/json-page-labels-and-outlines.out
+++ b/qpdf/qtest/qpdf/json-page-labels-and-outlines.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/json-page-labels-num-tree.out b/qpdf/qtest/qpdf/json-page-labels-num-tree.out
index 497f428c..d0f73a61 100644
--- a/qpdf/qtest/qpdf/json-page-labels-num-tree.out
+++ b/qpdf/qtest/qpdf/json-page-labels-num-tree.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/page_api_2-json.out b/qpdf/qtest/qpdf/page_api_2-json.out
index b8ce4f38..172ce1c1 100644
--- a/qpdf/qtest/qpdf/page_api_2-json.out
+++ b/qpdf/qtest/qpdf/page_api_2-json.out
@@ -4,6 +4,7 @@
"hasacroform": false,
"needappearances": false
},
+ "attachments": {},
"encrypt": {
"capabilities": {
"accessibility": true,
diff --git a/qpdf/qtest/qpdf/test76-json.out b/qpdf/qtest/qpdf/test76-json.out
new file mode 100644
index 00000000..d1c88cf8
--- /dev/null
+++ b/qpdf/qtest/qpdf/test76-json.out
@@ -0,0 +1,23 @@
+{
+ "attachments": {
+ "att1": {
+ "filespec": "4 0 R",
+ "preferredcontents": "8 0 R",
+ "preferredname": "att1.txt"
+ },
+ "att2": {
+ "filespec": "5 0 R",
+ "preferredcontents": "10 0 R",
+ "preferredname": "att2.txt"
+ },
+ "att3": {
+ "filespec": "6 0 R",
+ "preferredcontents": "12 0 R",
+ "preferredname": "π.txt"
+ }
+ },
+ "parameters": {
+ "decodelevel": "generalized"
+ },
+ "version": 1
+}