Commit ae9455bf449a22329507efd01455d5e9322cf134

Authored by Jay Berkenbilt
1 parent ce714ac9

Implement --json-objects

Showing 1 changed file with 60 additions and 19 deletions
qpdf/qpdf.cc
@@ -195,6 +195,7 @@ struct Options @@ -195,6 +195,7 @@ struct Options
195 bool show_page_images; 195 bool show_page_images;
196 bool json; 196 bool json;
197 std::set<std::string> json_keys; 197 std::set<std::string> json_keys;
  198 + std::set<std::string> json_objects;
198 bool check; 199 bool check;
199 std::vector<PageSpec> page_specs; 200 std::vector<PageSpec> page_specs;
200 std::map<std::string, RotationSpec> rotations; 201 std::map<std::string, RotationSpec> rotations;
@@ -344,6 +345,26 @@ static JSON json_schema(std::set&lt;std::string&gt;* keys = 0) @@ -344,6 +345,26 @@ static JSON json_schema(std::set&lt;std::string&gt;* keys = 0)
344 return schema; 345 return schema;
345 } 346 }
346 347
  348 +static void parse_object_id(std::string const& objspec,
  349 + bool& trailer, int& obj, int& gen)
  350 +{
  351 + if (objspec == "trailer")
  352 + {
  353 + trailer = true;
  354 + }
  355 + else
  356 + {
  357 + trailer = false;
  358 + obj = QUtil::string_to_int(objspec.c_str());
  359 + size_t comma = objspec.find(',');
  360 + if ((comma != std::string::npos) && (comma + 1 < objspec.length()))
  361 + {
  362 + gen = QUtil::string_to_int(
  363 + objspec.substr(1 + comma, std::string::npos).c_str());
  364 + }
  365 + }
  366 +}
  367 +
347 // This is not a general-purpose argument parser. It is tightly 368 // This is not a general-purpose argument parser. It is tightly
348 // crafted to work with qpdf. qpdf's command-line syntax is very 369 // crafted to work with qpdf. qpdf's command-line syntax is very
349 // complex because of its long history, and it doesn't really follow 370 // complex because of its long history, and it doesn't really follow
@@ -437,6 +458,7 @@ class ArgParser @@ -437,6 +458,7 @@ class ArgParser
437 void argWithImages(); 458 void argWithImages();
438 void argJson(); 459 void argJson();
439 void argJsonKey(char* parameter); 460 void argJsonKey(char* parameter);
  461 + void argJsonObject(char* parameter);
440 void argCheck(); 462 void argCheck();
441 void arg40Print(char* parameter); 463 void arg40Print(char* parameter);
442 void arg40Modify(char* parameter); 464 void arg40Modify(char* parameter);
@@ -638,6 +660,8 @@ ArgParser::initOptionTable() @@ -638,6 +660,8 @@ ArgParser::initOptionTable()
638 char const* jsonKeyChoices[] = {"objects", "pages", "pagelabels", 0}; 660 char const* jsonKeyChoices[] = {"objects", "pages", "pagelabels", 0};
639 (*t)["json-key"] = oe_requiredChoices( 661 (*t)["json-key"] = oe_requiredChoices(
640 &ArgParser::argJsonKey, jsonKeyChoices); 662 &ArgParser::argJsonKey, jsonKeyChoices);
  663 + (*t)["json-object"] = oe_requiredParameter(
  664 + &ArgParser::argJsonObject, "trailer|obj[,gen]");
641 (*t)["check"] = oe_bare(&ArgParser::argCheck); 665 (*t)["check"] = oe_bare(&ArgParser::argCheck);
642 666
643 t = &this->encrypt40_option_table; 667 t = &this->encrypt40_option_table;
@@ -1143,21 +1167,7 @@ ArgParser::argShowXref() @@ -1143,21 +1167,7 @@ ArgParser::argShowXref()
1143 void 1167 void
1144 ArgParser::argShowObject(char* parameter) 1168 ArgParser::argShowObject(char* parameter)
1145 { 1169 {
1146 - if (strcmp(parameter, "trailer") == 0)  
1147 - {  
1148 - o.show_trailer = true;  
1149 - }  
1150 - else  
1151 - {  
1152 - char* obj = parameter;  
1153 - char* gen = obj;  
1154 - if ((gen = strchr(obj, ',')) != 0)  
1155 - {  
1156 - *gen++ = 0;  
1157 - o.show_gen = QUtil::string_to_int(gen);  
1158 - }  
1159 - o.show_obj = QUtil::string_to_int(obj);  
1160 - } 1170 + parse_object_id(parameter, o.show_trailer, o.show_obj, o.show_gen);
1161 o.require_outfile = false; 1171 o.require_outfile = false;
1162 } 1172 }
1163 1173
@@ -1207,6 +1217,12 @@ ArgParser::argJsonKey(char* parameter) @@ -1207,6 +1217,12 @@ ArgParser::argJsonKey(char* parameter)
1207 } 1217 }
1208 1218
1209 void 1219 void
  1220 +ArgParser::argJsonObject(char* parameter)
  1221 +{
  1222 + o.json_objects.insert(parameter);
  1223 +}
  1224 +
  1225 +void
1210 ArgParser::argCheck() 1226 ArgParser::argCheck()
1211 { 1227 {
1212 o.check = true; 1228 o.check = true;
@@ -1691,7 +1707,11 @@ automated test suites for software that uses the qpdf library.\n\ @@ -1691,7 +1707,11 @@ automated test suites for software that uses the qpdf library.\n\
1691 --json generate a json representation of the file\n\ 1707 --json generate a json representation of the file\n\
1692 --json-help describe the format of the json representation\n\ 1708 --json-help describe the format of the json representation\n\
1693 --json-key=key repeatable; prune json structure to include only\n\ 1709 --json-key=key repeatable; prune json structure to include only\n\
1694 - specified keys\n\ 1710 + specified keys. If absent, all keys are shown\n\
  1711 +--json-object=trailer|[obj,gen]\n\
  1712 + repeatable; include only specified objects in the\n\
  1713 + \"objects\" section of the json. If absent, all\n\
  1714 + objects are shown\n\
1695 \n\ 1715 \n\
1696 The json representation generated by qpdf is designed to facilitate\n\ 1716 The json representation generated by qpdf is designed to facilitate\n\
1697 processing of qpdf from other programming languages that have a hard\n\ 1717 processing of qpdf from other programming languages that have a hard\n\
@@ -2586,14 +2606,35 @@ static void do_json_objects(QPDF&amp; pdf, Options&amp; o, JSON&amp; j) @@ -2586,14 +2606,35 @@ static void do_json_objects(QPDF&amp; pdf, Options&amp; o, JSON&amp; j)
2586 // Add all objects. Do this first before other code below modifies 2606 // Add all objects. Do this first before other code below modifies
2587 // things by doing stuff like calling 2607 // things by doing stuff like calling
2588 // pushInheritedAttributesToPage. 2608 // pushInheritedAttributesToPage.
  2609 + bool all_objects = o.json_objects.empty();
  2610 + std::set<QPDFObjGen> wanted_og;
  2611 + for (std::set<std::string>::iterator iter = o.json_objects.begin();
  2612 + iter != o.json_objects.end(); ++iter)
  2613 + {
  2614 + bool trailer;
  2615 + int obj = 0;
  2616 + int gen = 0;
  2617 + parse_object_id(*iter, trailer, obj, gen);
  2618 + if (obj)
  2619 + {
  2620 + wanted_og.insert(QPDFObjGen(obj, gen));
  2621 + }
  2622 + }
2589 JSON j_objects = j.addDictionaryMember("objects", JSON::makeDictionary()); 2623 JSON j_objects = j.addDictionaryMember("objects", JSON::makeDictionary());
2590 - j_objects.addDictionaryMember("trailer", pdf.getTrailer().getJSON(true)); 2624 + if (all_objects || o.json_objects.count("trailer"))
  2625 + {
  2626 + j_objects.addDictionaryMember(
  2627 + "trailer", pdf.getTrailer().getJSON(true));
  2628 + }
2591 std::vector<QPDFObjectHandle> objects = pdf.getAllObjects(); 2629 std::vector<QPDFObjectHandle> objects = pdf.getAllObjects();
2592 for (std::vector<QPDFObjectHandle>::iterator iter = objects.begin(); 2630 for (std::vector<QPDFObjectHandle>::iterator iter = objects.begin();
2593 iter != objects.end(); ++iter) 2631 iter != objects.end(); ++iter)
2594 { 2632 {
2595 - j_objects.addDictionaryMember(  
2596 - (*iter).unparse(), (*iter).getJSON(true)); 2633 + if (all_objects || wanted_og.count((*iter).getObjGen()))
  2634 + {
  2635 + j_objects.addDictionaryMember(
  2636 + (*iter).unparse(), (*iter).getJSON(true));
  2637 + }
2597 } 2638 }
2598 } 2639 }
2599 2640