Commit e3506253f17137d6d4831b4615d74689446da72c

Authored by Jay Berkenbilt
1 parent b4fb9b4e

Add optional version to --json

ChangeLog
  1 +2022-01-31 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Allow optional version number or "latest" as parameter to
  4 + --json, allowing for future specification of json version.
  5 +
1 2022-01-28 Jay Berkenbilt <ejb@ql.org> 6 2022-01-28 Jay Berkenbilt <ejb@ql.org>
2 7
3 * Add QPDFUsage exception, which is thrown by JSONHandler, 8 * Add QPDFUsage exception, which is thrown by JSONHandler,
include/qpdf/QPDFJob.hh
@@ -595,7 +595,7 @@ class QPDFJob @@ -595,7 +595,7 @@ class QPDFJob
595 std::list<std::string> attachments_to_remove; 595 std::list<std::string> attachments_to_remove;
596 std::list<AddAttachment> attachments_to_add; 596 std::list<AddAttachment> attachments_to_add;
597 std::list<CopyAttachmentFrom> attachments_to_copy; 597 std::list<CopyAttachmentFrom> attachments_to_copy;
598 - bool json; 598 + int json_version;
599 std::set<std::string> json_keys; 599 std::set<std::string> json_keys;
600 std::set<std::string> json_objects; 600 std::set<std::string> json_objects;
601 bool check; 601 bool check;
include/qpdf/auto_job_c_main.hh
@@ -15,7 +15,6 @@ QPDF_DLL Config* flattenRotation(); @@ -15,7 +15,6 @@ QPDF_DLL Config* flattenRotation();
15 QPDF_DLL Config* generateAppearances(); 15 QPDF_DLL Config* generateAppearances();
16 QPDF_DLL Config* ignoreXrefStreams(); 16 QPDF_DLL Config* ignoreXrefStreams();
17 QPDF_DLL Config* isEncrypted(); 17 QPDF_DLL Config* isEncrypted();
18 -QPDF_DLL Config* json();  
19 QPDF_DLL Config* keepInlineImages(); 18 QPDF_DLL Config* keepInlineImages();
20 QPDF_DLL Config* linearize(); 19 QPDF_DLL Config* linearize();
21 QPDF_DLL Config* listAttachments(); 20 QPDF_DLL Config* listAttachments();
@@ -76,3 +75,4 @@ QPDF_DLL Config* objectStreams(char const* parameter); @@ -76,3 +75,4 @@ QPDF_DLL Config* objectStreams(char const* parameter);
76 QPDF_DLL Config* passwordMode(char const* parameter); 75 QPDF_DLL Config* passwordMode(char const* parameter);
77 QPDF_DLL Config* removeUnreferencedResources(char const* parameter); 76 QPDF_DLL Config* removeUnreferencedResources(char const* parameter);
78 QPDF_DLL Config* streamData(char const* parameter); 77 QPDF_DLL Config* streamData(char const* parameter);
  78 +QPDF_DLL Config* json(char const* parameter);
job.sums
@@ -3,15 +3,15 @@ generate_auto_job ef1b438aeebed7ca0afcbe4d1f9c54d3acf899aec8410ebc69cd15ec673dd1 @@ -3,15 +3,15 @@ generate_auto_job ef1b438aeebed7ca0afcbe4d1f9c54d3acf899aec8410ebc69cd15ec673dd1
3 include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e 3 include/qpdf/auto_job_c_att.hh 7ad43bb374c1370ef32ebdcdcb7b73a61d281f7f4e3f12755585872ab30fb60e
4 include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee 4 include/qpdf/auto_job_c_copy_att.hh 32275d03cdc69b703dd7e02ba0bbe15756e714e9ad185484773a6178dc09e1ee
5 include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265 5 include/qpdf/auto_job_c_enc.hh 72e138c7b96ed5aacdce78c1dec04b1c20d361faec4f8faf52f64c1d6be99265
6 -include/qpdf/auto_job_c_main.hh 516adb23cc7e44e614e436880be870d0574e4ebbc706cd855a1360000eed31bb 6 +include/qpdf/auto_job_c_main.hh ff776dd643279330fbf59770d1abf5aaeb13f20bfc5f6a25997aaa72a0907b44
7 include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671 7 include/qpdf/auto_job_c_pages.hh 931840b329a36ca0e41401190e04537b47f2867671a6643bfd8da74014202671
8 include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50 8 include/qpdf/auto_job_c_uo.hh 0585b7de459fa479d9e51a45fa92de0ff6dee748efc9ec1cedd0dde6cee1ad50
9 -job.yml 498459e6c2b7a9bc13168cd58fed75dbd24394fc187230ff7179a22288fa0de5 9 +job.yml c3e714b3c3e2fc85390d983302ff398aa0992c621e85dbcaee20173b1bd3cb0b
10 libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6 10 libqpdf/qpdf/auto_job_decl.hh 9f79396ec459f191be4c5fe34cf88c265cf47355a1a945fa39169d1c94cf04f6
11 -libqpdf/qpdf/auto_job_help.hh 23c79f1d2c02bda28f64aace17f69487205c797e7ae2234892cbbabab49d6d47  
12 -libqpdf/qpdf/auto_job_init.hh 8e9e31b6099a662497339b27f6e2d7f779f35011e88a834bee8811c33405a0fe 11 +libqpdf/qpdf/auto_job_help.hh a0ab6ab4dde2ad3d3f17ecae3ea274919119329e075061f3a3973535f5e367de
  12 +libqpdf/qpdf/auto_job_init.hh c244e03e8b83ed7db732920f40aff0134e5f2e78a6edb9473ea4dd1934a8953e
13 libqpdf/qpdf/auto_job_json_decl.hh 741a44106f7850b6cbc8af264b5b77bb605475c8d8dd8cd87011d5debbee6269 13 libqpdf/qpdf/auto_job_json_decl.hh 741a44106f7850b6cbc8af264b5b77bb605475c8d8dd8cd87011d5debbee6269
14 -libqpdf/qpdf/auto_job_json_init.hh 886dd8ed7ae7691eaa97a0e5b3f1445f4cccab88ed372f530a8524d198c8f1d9 14 +libqpdf/qpdf/auto_job_json_init.hh 63bbe1c3d673cd56196ec42ec7ede7b531563667d83564aa6680634fcb2cf259
15 libqpdf/qpdf/auto_job_schema.hh a764050cc99f1cc95645fd1ea2f020c4b778957abc64fbc55c12eac3a369dc92 15 libqpdf/qpdf/auto_job_schema.hh a764050cc99f1cc95645fd1ea2f020c4b778957abc64fbc55c12eac3a369dc92
16 manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3 16 manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3
17 -manual/cli.rst 79140e023faa0cb77afe0b1dc512dd120ee5617f4db82f842596e4f239f93882 17 +manual/cli.rst a75a7e34aa9aba4f06e9c88cae9a2d9a2aa4e55a08521dde1478e8f2d80aadab
@@ -29,6 +29,9 @@ choices: @@ -29,6 +29,9 @@ choices:
29 - all 29 - all
30 - print 30 - print
31 - screen 31 - screen
  32 + json_version:
  33 + - 1
  34 + - latest
32 json_key: 35 json_key:
33 # The list of selectable top-level keys id duplicated in the 36 # The list of selectable top-level keys id duplicated in the
34 # following places: job.yml, QPDFJob::json_schema, and 37 # following places: job.yml, QPDFJob::json_schema, and
@@ -88,7 +91,6 @@ options: @@ -88,7 +91,6 @@ options:
88 - generate-appearances 91 - generate-appearances
89 - ignore-xref-streams 92 - ignore-xref-streams
90 - is-encrypted 93 - is-encrypted
91 - - json  
92 - keep-inline-images 94 - keep-inline-images
93 - linearize 95 - linearize
94 - list-attachments 96 - list-attachments
@@ -156,6 +158,8 @@ options: @@ -156,6 +158,8 @@ options:
156 password-mode: password_mode 158 password-mode: password_mode
157 remove-unreferenced-resources: remove_unref 159 remove-unreferenced-resources: remove_unref
158 stream-data: stream_data 160 stream-data: stream_data
  161 + optional_choices:
  162 + json: json_version
159 - table: pages 163 - table: pages
160 config: c_pages 164 config: c_pages
161 prefix: Pages 165 prefix: Pages
libqpdf/QPDFJob.cc
@@ -420,7 +420,7 @@ QPDFJob::Members::Members() : @@ -420,7 +420,7 @@ QPDFJob::Members::Members() :
420 collate(0), 420 collate(0),
421 flatten_rotation(false), 421 flatten_rotation(false),
422 list_attachments(false), 422 list_attachments(false),
423 - json(false), 423 + json_version(0),
424 check(false), 424 check(false),
425 optimize_images(false), 425 optimize_images(false),
426 externalize_inline_images(false), 426 externalize_inline_images(false),
@@ -1924,7 +1924,7 @@ QPDFJob::doInspection(QPDF&amp; pdf) @@ -1924,7 +1924,7 @@ QPDFJob::doInspection(QPDF&amp; pdf)
1924 { 1924 {
1925 doCheck(pdf); 1925 doCheck(pdf);
1926 } 1926 }
1927 - if (m->json) 1927 + if (m->json_version)
1928 { 1928 {
1929 doJSON(pdf); 1929 doJSON(pdf);
1930 } 1930 }
libqpdf/QPDFJob_config.cc
@@ -235,9 +235,27 @@ QPDFJob::Config::isEncrypted() @@ -235,9 +235,27 @@ QPDFJob::Config::isEncrypted()
235 } 235 }
236 236
237 QPDFJob::Config* 237 QPDFJob::Config*
238 -QPDFJob::Config::json() 238 +QPDFJob::Config::json(char const* parameter)
239 { 239 {
240 - o.m->json = true; 240 + if (parameter)
  241 + {
  242 + if (strcmp(parameter, "latest") == 0)
  243 + {
  244 + o.m->json_version = 1;
  245 + }
  246 + else
  247 + {
  248 + o.m->json_version = QUtil::string_to_int(parameter);
  249 + }
  250 + }
  251 + else
  252 + {
  253 + o.m->json_version = 1;
  254 + }
  255 + if (o.m->json_version != 1)
  256 + {
  257 + usage(std::string("unsupported json version ") + parameter);
  258 + }
241 o.m->require_outfile = false; 259 o.m->require_outfile = false;
242 return this; 260 return this;
243 } 261 }
libqpdf/qpdf/auto_job_help.hh
@@ -788,8 +788,11 @@ output as binary data. Get the key with --list-attachments. @@ -788,8 +788,11 @@ output as binary data. Get the key with --list-attachments.
788 ap.addHelpTopic("json", "JSON output for PDF information", R"(Show information about the PDF file in JSON format. Please see the 788 ap.addHelpTopic("json", "JSON output for PDF information", R"(Show information about the PDF file in JSON format. Please see the
789 JSON chapter in the qpdf manual for details. 789 JSON chapter in the qpdf manual for details.
790 )"); 790 )");
791 -ap.addOptionHelp("--json", "json", "show file in json format", R"(Generate a JSON representation of the file. This is described in  
792 -depth in the JSON section of the manual. 791 +ap.addOptionHelp("--json", "json", "show file in json format", R"(--json[=version]
  792 +
  793 +Generate a JSON representation of the file. This is described in
  794 +depth in the JSON section of the manual. "version" may be a
  795 +specific version or "latest".
793 )"); 796 )");
794 ap.addOptionHelp("--json-help", "json", "show format of json output", R"(Describe the format of the JSON output. 797 ap.addOptionHelp("--json-help", "json", "show format of json output", R"(Describe the format of the JSON output.
795 )"); 798 )");
libqpdf/qpdf/auto_job_init.hh
@@ -17,6 +17,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized @@ -17,6 +17,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized
17 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; 17 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0};
18 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; 18 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0};
19 static char const* flatten_choices[] = {"all", "print", "screen", 0}; 19 static char const* flatten_choices[] = {"all", "print", "screen", 0};
  20 +static char const* json_version_choices[] = {"1", "latest", 0};
20 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; 21 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0};
21 static char const* print128_choices[] = {"full", "low", "none", 0}; 22 static char const* print128_choices[] = {"full", "low", "none", 0};
22 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; 23 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
@@ -45,7 +46,6 @@ this-&gt;ap.addBare(&quot;flatten-rotation&quot;, [this](){c_main-&gt;flattenRotation();}); @@ -45,7 +46,6 @@ this-&gt;ap.addBare(&quot;flatten-rotation&quot;, [this](){c_main-&gt;flattenRotation();});
45 this->ap.addBare("generate-appearances", [this](){c_main->generateAppearances();}); 46 this->ap.addBare("generate-appearances", [this](){c_main->generateAppearances();});
46 this->ap.addBare("ignore-xref-streams", [this](){c_main->ignoreXrefStreams();}); 47 this->ap.addBare("ignore-xref-streams", [this](){c_main->ignoreXrefStreams();});
47 this->ap.addBare("is-encrypted", [this](){c_main->isEncrypted();}); 48 this->ap.addBare("is-encrypted", [this](){c_main->isEncrypted();});
48 -this->ap.addBare("json", [this](){c_main->json();});  
49 this->ap.addBare("keep-inline-images", [this](){c_main->keepInlineImages();}); 49 this->ap.addBare("keep-inline-images", [this](){c_main->keepInlineImages();});
50 this->ap.addBare("linearize", [this](){c_main->linearize();}); 50 this->ap.addBare("linearize", [this](){c_main->linearize();});
51 this->ap.addBare("list-attachments", [this](){c_main->listAttachments();}); 51 this->ap.addBare("list-attachments", [this](){c_main->listAttachments();});
@@ -110,6 +110,7 @@ this-&gt;ap.addChoices(&quot;object-streams&quot;, [this](char *x){c_main-&gt;objectStreams(x);} @@ -110,6 +110,7 @@ this-&gt;ap.addChoices(&quot;object-streams&quot;, [this](char *x){c_main-&gt;objectStreams(x);}
110 this->ap.addChoices("password-mode", [this](char *x){c_main->passwordMode(x);}, true, password_mode_choices); 110 this->ap.addChoices("password-mode", [this](char *x){c_main->passwordMode(x);}, true, password_mode_choices);
111 this->ap.addChoices("remove-unreferenced-resources", [this](char *x){c_main->removeUnreferencedResources(x);}, true, remove_unref_choices); 111 this->ap.addChoices("remove-unreferenced-resources", [this](char *x){c_main->removeUnreferencedResources(x);}, true, remove_unref_choices);
112 this->ap.addChoices("stream-data", [this](char *x){c_main->streamData(x);}, true, stream_data_choices); 112 this->ap.addChoices("stream-data", [this](char *x){c_main->streamData(x);}, true, stream_data_choices);
  113 +this->ap.addChoices("json", [this](char *x){c_main->json(x);}, false, json_version_choices);
113 this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages)); 114 this->ap.registerOptionTable("pages", b(&ArgParser::argEndPages));
114 this->ap.addPositional(p(&ArgParser::argPagesPositional)); 115 this->ap.addPositional(p(&ArgParser::argPagesPositional));
115 this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password"); 116 this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password");
libqpdf/qpdf/auto_job_json_init.hh
@@ -10,6 +10,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized @@ -10,6 +10,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized
10 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; 10 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0};
11 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; 11 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0};
12 static char const* flatten_choices[] = {"all", "print", "screen", 0}; 12 static char const* flatten_choices[] = {"all", "print", "screen", 0};
  13 +static char const* json_version_choices[] = {"1", "latest", 0};
13 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; 14 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0};
14 static char const* print128_choices[] = {"full", "low", "none", 0}; 15 static char const* print128_choices[] = {"full", "low", "none", 0};
15 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; 16 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
@@ -248,7 +249,7 @@ pushKey(&quot;showAttachment&quot;); @@ -248,7 +249,7 @@ pushKey(&quot;showAttachment&quot;);
248 addParameter([this](char const* p) { c_main->showAttachment(p); }); 249 addParameter([this](char const* p) { c_main->showAttachment(p); });
249 popHandler(); // key: showAttachment 250 popHandler(); // key: showAttachment
250 pushKey("json"); 251 pushKey("json");
251 -addBare([this]() { c_main->json(); }); 252 +addChoices(json_version_choices, [this](char const* p) { c_main->json(p); });
252 popHandler(); // key: json 253 popHandler(); // key: json
253 pushKey("jsonKey"); 254 pushKey("jsonKey");
254 beginArray(bindJSON(&Handlers::beginInspectJsonKeyArray), bindBare(&Handlers::endInspectJsonKeyArray)); // .inspect.jsonKey[] 255 beginArray(bindJSON(&Handlers::beginInspectJsonKeyArray), bindBare(&Handlers::endInspectJsonKeyArray)); // .inspect.jsonKey[]
manual/cli.rst
@@ -3136,15 +3136,21 @@ See :ref:`json` for details about the qpdf JSON format. @@ -3136,15 +3136,21 @@ See :ref:`json` for details about the qpdf JSON format.
3136 Related Options 3136 Related Options
3137 ~~~~~~~~~~~~~~~ 3137 ~~~~~~~~~~~~~~~
3138 3138
3139 -.. qpdf:option:: --json 3139 +.. qpdf:option:: --json[=version]
3140 3140
3141 .. help: show file in json format 3141 .. help: show file in json format
3142 3142
3143 Generate a JSON representation of the file. This is described in 3143 Generate a JSON representation of the file. This is described in
3144 - depth in the JSON section of the manual. 3144 + depth in the JSON section of the manual. "version" may be a
  3145 + specific version or "latest".
3145 3146
3146 Generate a JSON representation of the file. This is described in 3147 Generate a JSON representation of the file. This is described in
3147 - depth in :ref:`json`. 3148 + depth in :ref:`json`. The version parameter can be used to specify
  3149 + which json version should be output. The only supported value is
  3150 + ``1``, but it's possible that a new json output version will be
  3151 + added in a future version. You can also specify ``latest`` to use
  3152 + the latest json version. For backward compatibility, the default
  3153 + value is ``1``.
3148 3154
3149 .. qpdf:option:: --json-help 3155 .. qpdf:option:: --json-help
3150 3156
qpdf/qtest/qpdf.test
@@ -617,7 +617,7 @@ $td-&gt;runtest(&quot;list attachments verbose&quot;, @@ -617,7 +617,7 @@ $td-&gt;runtest(&quot;list attachments verbose&quot;,
617 {$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0}, 617 {$td->FILE => "test76-list-verbose.out", $td->EXIT_STATUS => 0},
618 $td->NORMALIZE_NEWLINES); 618 $td->NORMALIZE_NEWLINES);
619 $td->runtest("attachments json", 619 $td->runtest("attachments json",
620 - {$td->COMMAND => "qpdf --json --json-key=attachments a.pdf"}, 620 + {$td->COMMAND => "qpdf --json=1 --json-key=attachments a.pdf"},
621 {$td->FILE => "test76-json.out", $td->EXIT_STATUS => 0}, 621 {$td->FILE => "test76-json.out", $td->EXIT_STATUS => 0},
622 $td->NORMALIZE_NEWLINES); 622 $td->NORMALIZE_NEWLINES);
623 $td->runtest("remove attachment (test_driver)", 623 $td->runtest("remove attachment (test_driver)",
@@ -2705,7 +2705,7 @@ $td-&gt;runtest(&quot;show direct pages&quot;, @@ -2705,7 +2705,7 @@ $td-&gt;runtest(&quot;show direct pages&quot;,
2705 foreach my $f (qw(page_api_2 direct-pages)) 2705 foreach my $f (qw(page_api_2 direct-pages))
2706 { 2706 {
2707 $td->runtest("json for $f", 2707 $td->runtest("json for $f",
2708 - {$td->COMMAND => "qpdf --json $f.pdf"}, 2708 + {$td->COMMAND => "qpdf --json=latest $f.pdf"},
2709 {$td->FILE => "$f-json.out", $td->EXIT_STATUS => 0}, 2709 {$td->FILE => "$f-json.out", $td->EXIT_STATUS => 0},
2710 $td->NORMALIZE_NEWLINES); 2710 $td->NORMALIZE_NEWLINES);
2711 } 2711 }