mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 19:08:59 +00:00
Add attachment information to the json output
This commit is contained in:
parent
832d792e4e
commit
accb891b4f
@ -1,5 +1,8 @@
|
|||||||
2021-02-10 Jay Berkenbilt <ejb@ql.org>
|
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:
|
* Add new command-line arguments for operating on attachments:
|
||||||
--list-attachments, --add-attachment, --remove-attachment,
|
--list-attachments, --add-attachment, --remove-attachment,
|
||||||
--copy-attachments-from. See --help and manual for details.
|
--copy-attachments-from. See --help and manual for details.
|
||||||
|
@ -5104,6 +5104,19 @@ print "\n";
|
|||||||
than using <option>@file</option> for this purpose.
|
than using <option>@file</option> for this purpose.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</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>
|
</itemizedlist>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
44
qpdf/qpdf.cc
44
qpdf/qpdf.cc
@ -699,6 +699,22 @@ static JSON json_schema(std::set<std::string>* keys = 0)
|
|||||||
"filemethod",
|
"filemethod",
|
||||||
JSON::makeString("encryption method for attachments"));
|
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;
|
return schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,7 +1130,7 @@ ArgParser::initOptionTable()
|
|||||||
// places: json_schema, do_json, and initOptionTable.
|
// places: json_schema, do_json, and initOptionTable.
|
||||||
char const* json_key_choices[] = {
|
char const* json_key_choices[] = {
|
||||||
"objects", "objectinfo", "pages", "pagelabels", "outlines",
|
"objects", "objectinfo", "pages", "pagelabels", "outlines",
|
||||||
"acroform", "encrypt", 0};
|
"acroform", "encrypt", "attachments", 0};
|
||||||
(*t)["json-key"] = oe_requiredChoices(
|
(*t)["json-key"] = oe_requiredChoices(
|
||||||
&ArgParser::argJsonKey, json_key_choices);
|
&ArgParser::argJsonKey, json_key_choices);
|
||||||
(*t)["json-object"] = oe_requiredParameter(
|
(*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));
|
"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)
|
static void do_json(QPDF& pdf, Options& o)
|
||||||
{
|
{
|
||||||
JSON j = JSON::makeDictionary();
|
JSON j = JSON::makeDictionary();
|
||||||
@ -4628,6 +4666,10 @@ static void do_json(QPDF& pdf, Options& o)
|
|||||||
{
|
{
|
||||||
do_json_encrypt(pdf, o, j);
|
do_json_encrypt(pdf, o, j);
|
||||||
}
|
}
|
||||||
|
if (all_keys || o.json_keys.count("attachments"))
|
||||||
|
{
|
||||||
|
do_json_attachments(pdf, o, j);
|
||||||
|
}
|
||||||
|
|
||||||
// Check against schema
|
// Check against schema
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ $td->runtest("page operations on form xobject",
|
|||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- File Attachments ---");
|
$td->notify("--- File Attachments ---");
|
||||||
$n_tests += 33;
|
$n_tests += 34;
|
||||||
|
|
||||||
open(F, ">auto-txt") or die;
|
open(F, ">auto-txt") or die;
|
||||||
print F "from file";
|
print F "from file";
|
||||||
@ -547,6 +547,10 @@ $td->runtest("list attachments verbose",
|
|||||||
{$td->COMMAND => "qpdf --list-attachments --verbose a.pdf"},
|
{$td->COMMAND => "qpdf --list-attachments --verbose a.pdf"},
|
||||||
{$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0},
|
{$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0},
|
||||||
$td->NORMALIZE_NEWLINES);
|
$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->runtest("remove attachment (test_driver)",
|
||||||
{$td->COMMAND => "test_driver 77 test76.pdf"},
|
{$td->COMMAND => "test_driver 77 test76.pdf"},
|
||||||
{$td->STRING => "test 77 done\n", $td->EXIT_STATUS => 0},
|
{$td->STRING => "test 77 done\n", $td->EXIT_STATUS => 0},
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -385,6 +385,7 @@
|
|||||||
"hasacroform": true,
|
"hasacroform": true,
|
||||||
"needappearances": true
|
"needappearances": true
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -385,6 +385,7 @@
|
|||||||
"hasacroform": true,
|
"hasacroform": true,
|
||||||
"needappearances": true
|
"needappearances": true
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"hasacroform": false,
|
"hasacroform": false,
|
||||||
"needappearances": false
|
"needappearances": false
|
||||||
},
|
},
|
||||||
|
"attachments": {},
|
||||||
"encrypt": {
|
"encrypt": {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"accessibility": true,
|
"accessibility": true,
|
||||||
|
23
qpdf/qtest/qpdf/test76-json.out
Normal file
23
qpdf/qtest/qpdf/test76-json.out
Normal file
@ -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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user