2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-06-04 03:10:52 +00:00

Add attachment information to the json output

This commit is contained in:
Jay Berkenbilt 2021-02-10 15:35:01 -05:00
parent 832d792e4e
commit accb891b4f
17 changed files with 99 additions and 2 deletions

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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},

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -385,6 +385,7 @@
"hasacroform": true, "hasacroform": true,
"needappearances": true "needappearances": true
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -385,6 +385,7 @@
"hasacroform": true, "hasacroform": true,
"needappearances": true "needappearances": true
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View File

@ -4,6 +4,7 @@
"hasacroform": false, "hasacroform": false,
"needappearances": false "needappearances": false
}, },
"attachments": {},
"encrypt": { "encrypt": {
"capabilities": { "capabilities": {
"accessibility": true, "accessibility": true,

View 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
}