Commit 16f4f94cd99b4d0f633596074e8d9358db135517

Authored by Jay Berkenbilt
1 parent a9fbbd5d

Prepare code for JSON v2

Update getJSON() methods and calls to them
Showing 55 changed files with 177 additions and 99 deletions
@@ -50,8 +50,6 @@ Output JSON v2 @@ -50,8 +50,6 @@ Output JSON v2
50 50
51 General things to remember: 51 General things to remember:
52 52
53 -* deprecate getJSON without a version  
54 -  
55 * Make sure all the information from --check and other informational 53 * Make sure all the information from --check and other informational
56 options (--show-linearization, --show-encryption, --show-xref, 54 options (--show-linearization, --show-encryption, --show-xref,
57 --list-attachments, --show-npages) is available in the json output. 55 --list-attachments, --show-npages) is available in the json output.
fuzz/qpdf_fuzzer.cc
@@ -142,7 +142,7 @@ FuzzHelper::testPages() @@ -142,7 +142,7 @@ FuzzHelper::testPages()
142 page.getImages(); 142 page.getImages();
143 pldh.getLabelForPage(pageno); 143 pldh.getLabelForPage(pageno);
144 QPDFObjectHandle page_obj(page.getObjectHandle()); 144 QPDFObjectHandle page_obj(page.getObjectHandle());
145 - page_obj.getJSON(true).unparse(); 145 + page_obj.getJSON(JSON::LATEST, true).unparse();
146 odh.getOutlinesForPage(page_obj.getObjGen()); 146 odh.getOutlinesForPage(page_obj.getObjGen());
147 147
148 std::vector<QPDFAnnotationObjectHelper> annotations = 148 std::vector<QPDFAnnotationObjectHelper> annotations =
include/qpdf/JSON.hh
@@ -51,6 +51,8 @@ class InputSource; @@ -51,6 +51,8 @@ class InputSource;
51 class JSON 51 class JSON
52 { 52 {
53 public: 53 public:
  54 + static int constexpr LATEST = 2;
  55 +
54 QPDF_DLL 56 QPDF_DLL
55 std::string unparse() const; 57 std::string unparse() const;
56 58
include/qpdf/QPDFJob.hh
@@ -26,6 +26,7 @@ @@ -26,6 +26,7 @@
26 #include <qpdf/DLL.h> 26 #include <qpdf/DLL.h>
27 #include <qpdf/PDFVersion.hh> 27 #include <qpdf/PDFVersion.hh>
28 #include <qpdf/QPDF.hh> 28 #include <qpdf/QPDF.hh>
  29 +#include <qpdf/QPDFOutlineObjectHelper.hh>
29 #include <qpdf/QPDFPageObjectHelper.hh> 30 #include <qpdf/QPDFPageObjectHelper.hh>
30 31
31 #include <functional> 32 #include <functional>
@@ -520,6 +521,10 @@ class QPDFJob @@ -520,6 +521,10 @@ class QPDFJob
520 void doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf); 521 void doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf);
521 void doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf); 522 void doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf);
522 void doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf); 523 void doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf);
  524 + void addOutlinesToJson(
  525 + std::vector<QPDFOutlineObjectHelper> outlines,
  526 + JSON& j,
  527 + std::map<QPDFObjGen, int>& page_numbers);
523 528
524 enum remove_unref_e { re_auto, re_yes, re_no }; 529 enum remove_unref_e { re_auto, re_yes, re_no };
525 530
include/qpdf/QPDFObject.hh
@@ -64,7 +64,7 @@ class QPDFObject @@ -64,7 +64,7 @@ class QPDFObject
64 64
65 virtual ~QPDFObject() = default; 65 virtual ~QPDFObject() = default;
66 virtual std::string unparse() = 0; 66 virtual std::string unparse() = 0;
67 - virtual JSON getJSON() = 0; 67 + virtual JSON getJSON(int json_version) = 0;
68 68
69 // Return a unique type code for the object 69 // Return a unique type code for the object
70 virtual object_type_e getTypeCode() const = 0; 70 virtual object_type_e getTypeCode() const = 0;
include/qpdf/QPDFObjectHandle.hh
@@ -1304,15 +1304,40 @@ class QPDFObjectHandle @@ -1304,15 +1304,40 @@ class QPDFObjectHandle
1304 QPDF_DLL 1304 QPDF_DLL
1305 std::string unparseBinary(); 1305 std::string unparseBinary();
1306 1306
1307 - // Return encoded as JSON. For most object types, there is an  
1308 - // obvious mapping. The JSON is generated as follows:  
1309 - // * Names are encoded as strings representing the normalized name  
1310 - // in PDF syntax as returned by unparse() 1307 + // Return encoded as JSON. The constant JSON::LATEST can be used
  1308 + // to specify the latest available JSON version. The JSON is
  1309 + // generated as follows:
  1310 + // * Arrays, dictionaries, booleans, nulls, integers, and real
  1311 + // numbers are represented by their native JSON types.
  1312 + // * Names are encoded as strings representing the canonical
  1313 + // representation (after parsing #xx) and preceded by a slash,
  1314 + // just as unparse() returns. For example, the JSON for the
  1315 + // PDF-syntax name /Text#2fPlain would be "/Text/Plain".
1311 // * Indirect references are encoded as strings containing "obj gen R" 1316 // * Indirect references are encoded as strings containing "obj gen R"
1312 - // * Strings are encoded as UTF-8 strings with unrepresentable binary  
1313 - // characters encoded as \uHHHH  
1314 - // * Encoding streams just encodes the stream's dictionary; the stream  
1315 - // data is not represented 1317 + // * Strings
  1318 + // * JSON v1: Strings are encoded as UTF-8 strings with
  1319 + // unrepresentable binary characters encoded as \uHHHH.
  1320 + // Characters in PDF Doc encoding that don't have
  1321 + // bidirectional unicode mappings are not reversible. There is
  1322 + // no way to tell the difference between a string that looks
  1323 + // like a name or indirect object from an actual name or
  1324 + // indirect object.
  1325 + // * JSON v2:
  1326 + // * Unicode strings and strings encoded with PDF Doc encoding
  1327 + // that can be bidrectionally mapped two Unicode (which is
  1328 + // all strings without undefined characters) are represented
  1329 + // as "u:" followed by the UTF-8 encoded string. Example:
  1330 + // "u:potato".
  1331 + // * All other strings are represented as "b:" followed by a
  1332 + // hexadecimal encoding of the string. Example: "b:0102cacb"
  1333 + // * Streams
  1334 + // * JSON v1: Only the stream's dictionary is encoded. There is
  1335 + // no way tell a stream from a dictionary other than context.
  1336 + // * JSON v2: A stream is encoded as {"dict": {...}} with the
  1337 + // value being the encoding of the stream's dictionary. Since
  1338 + // "dict" does not otherwise represent anything, this is
  1339 + // unambiguous. The getStreamJSON() call can be used to add
  1340 + // encoding of the stream's data.
1316 // * Object types that are only valid in content streams (inline 1341 // * Object types that are only valid in content streams (inline
1317 // image, operator) as well as "reserved" objects are not 1342 // image, operator) as well as "reserved" objects are not
1318 // representable and will be serialized as "null". 1343 // representable and will be serialized as "null".
@@ -1321,6 +1346,12 @@ class QPDFObjectHandle @@ -1321,6 +1346,12 @@ class QPDFObjectHandle
1321 // dereference_indirect applies only to this object. It is not 1346 // dereference_indirect applies only to this object. It is not
1322 // recursive. 1347 // recursive.
1323 QPDF_DLL 1348 QPDF_DLL
  1349 + JSON getJSON(int json_version, bool dereference_indirect = false);
  1350 +
  1351 + // Deprecated version uses v1 for backward compatibility.
  1352 + // ABI: remove for qpdf 12
  1353 + [[deprecated("Use getJSON(int version)")]]
  1354 + QPDF_DLL
1324 JSON getJSON(bool dereference_indirect = false); 1355 JSON getJSON(bool dereference_indirect = false);
1325 1356
1326 // Legacy helper methods for commonly performed operations on 1357 // Legacy helper methods for commonly performed operations on
job.sums
@@ -6,12 +6,12 @@ include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a3 @@ -6,12 +6,12 @@ include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a3
6 include/qpdf/auto_job_c_main.hh 940aa6f1ead18ed08ba33f11254e9f042348262c85b91de742f0427094412a80 6 include/qpdf/auto_job_c_main.hh 940aa6f1ead18ed08ba33f11254e9f042348262c85b91de742f0427094412a80
7 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec 7 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
8 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 8 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
9 -job.yml 3c130913b3546f272c06b334ece9aa70450449539db10e39673b5ee79d863f48 9 +job.yml e3d9752ea8810872447190b0b2b913f591ae03dfdd876945adf1bbb76942cd0f
10 libqpdf/qpdf/auto_job_decl.hh 74df4d7fdbdf51ecd0d58ce1e9844bb5525b9adac5a45f7c9a787ecdda2868df 10 libqpdf/qpdf/auto_job_decl.hh 74df4d7fdbdf51ecd0d58ce1e9844bb5525b9adac5a45f7c9a787ecdda2868df
11 libqpdf/qpdf/auto_job_help.hh a3d1a326a3f8ff61a7d451176acde3bb6c8ad66c1ea7a0b8c5d789917ad3a9ee 11 libqpdf/qpdf/auto_job_help.hh a3d1a326a3f8ff61a7d451176acde3bb6c8ad66c1ea7a0b8c5d789917ad3a9ee
12 -libqpdf/qpdf/auto_job_init.hh c8477a597f037d7de5fd131b008a75f1fe435bba248261abe422e8bfb24c8755 12 +libqpdf/qpdf/auto_job_init.hh 1dcefadac02bb4b3a5d112912483902ad46489b1cacefefd3ebe4f64fc1b8a29
13 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297 13 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297
14 -libqpdf/qpdf/auto_job_json_init.hh e7047a7c83737adfaae49abc295a579bb9b9e0a4644e911d1656a604cb202208 14 +libqpdf/qpdf/auto_job_json_init.hh 784ff973e7efbf589f6a9b3ad22b3aada5c5393e9c5cd31845b8fe4af6e03f98
15 libqpdf/qpdf/auto_job_schema.hh cbbcae166cfecbdbdeb40c5a30870e03604a019a8b4f7a217d554a82431d2e5f 15 libqpdf/qpdf/auto_job_schema.hh cbbcae166cfecbdbdeb40c5a30870e03604a019a8b4f7a217d554a82431d2e5f
16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 16 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
17 manual/cli.rst 8684ca1f601f2832cded52d1b2f74730f97b7b85b57e31a399231731fbe80d26 17 manual/cli.rst 8684ca1f601f2832cded52d1b2f74730f97b7b85b57e31a399231731fbe80d26
@@ -38,6 +38,7 @@ choices: @@ -38,6 +38,7 @@ choices:
38 - screen 38 - screen
39 json_version: 39 json_version:
40 - 1 40 - 1
  41 + - 2
41 - latest 42 - latest
42 json_key: 43 json_key:
43 # The list of selectable top-level keys id duplicated in the 44 # The list of selectable top-level keys id duplicated in the
libqpdf/QPDFJob.cc
@@ -1053,12 +1053,20 @@ QPDFJob::doJSONObjects(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1053,12 +1053,20 @@ QPDFJob::doJSONObjects(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1053 for (auto& obj: objects) { 1053 for (auto& obj: objects) {
1054 if (all_objects || wanted_og.count(obj.getObjGen())) { 1054 if (all_objects || wanted_og.count(obj.getObjGen())) {
1055 JSON::writeDictionaryItem( 1055 JSON::writeDictionaryItem(
1056 - p, first_object, obj.unparse(), obj.getJSON(true), 1); 1056 + p,
  1057 + first_object,
  1058 + obj.unparse(),
  1059 + obj.getJSON(this->m->json_version, true),
  1060 + 1);
1057 } 1061 }
1058 } 1062 }
1059 if (all_objects || m->json_objects.count("trailer")) { 1063 if (all_objects || m->json_objects.count("trailer")) {
1060 JSON::writeDictionaryItem( 1064 JSON::writeDictionaryItem(
1061 - p, first_object, "trailer", pdf.getTrailer().getJSON(true), 1); 1065 + p,
  1066 + first_object,
  1067 + "trailer",
  1068 + pdf.getTrailer().getJSON(this->m->json_version, true),
  1069 + 1);
1062 } 1070 }
1063 JSON::writeDictionaryClose(p, first_object, 1); 1071 JSON::writeDictionaryClose(p, first_object, 1);
1064 } 1072 }
@@ -1080,11 +1088,13 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1080,11 +1088,13 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1080 j_stream.addDictionaryMember("is", JSON::makeBool(is_stream)); 1088 j_stream.addDictionaryMember("is", JSON::makeBool(is_stream));
1081 j_stream.addDictionaryMember( 1089 j_stream.addDictionaryMember(
1082 "length", 1090 "length",
1083 - (is_stream ? obj.getDict().getKey("/Length").getJSON(true) 1091 + (is_stream ? obj.getDict().getKey("/Length").getJSON(
  1092 + this->m->json_version, true)
1084 : JSON::makeNull())); 1093 : JSON::makeNull()));
1085 j_stream.addDictionaryMember( 1094 j_stream.addDictionaryMember(
1086 "filter", 1095 "filter",
1087 - (is_stream ? obj.getDict().getKey("/Filter").getJSON(true) 1096 + (is_stream ? obj.getDict().getKey("/Filter").getJSON(
  1097 + this->m->json_version, true)
1088 : JSON::makeNull())); 1098 : JSON::makeNull()));
1089 JSON::writeDictionaryItem( 1099 JSON::writeDictionaryItem(
1090 p, first_object, obj.unparse(), j_details, 1); 1100 p, first_object, obj.unparse(), j_details, 1);
@@ -1108,7 +1118,8 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1108,7 +1118,8 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1108 ++pageno; 1118 ++pageno;
1109 JSON j_page = JSON::makeDictionary(); 1119 JSON j_page = JSON::makeDictionary();
1110 QPDFObjectHandle page = ph.getObjectHandle(); 1120 QPDFObjectHandle page = ph.getObjectHandle();
1111 - j_page.addDictionaryMember("object", page.getJSON()); 1121 + j_page.addDictionaryMember(
  1122 + "object", page.getJSON(this->m->json_version));
1112 JSON j_images = j_page.addDictionaryMember("images", JSON::makeArray()); 1123 JSON j_images = j_page.addDictionaryMember("images", JSON::makeArray());
1113 std::map<std::string, QPDFObjectHandle> images = ph.getImages(); 1124 std::map<std::string, QPDFObjectHandle> images = ph.getImages();
1114 for (auto const& iter2: images) { 1125 for (auto const& iter2: images) {
@@ -1116,17 +1127,23 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1116,17 +1127,23 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1116 j_image.addDictionaryMember("name", JSON::makeString(iter2.first)); 1127 j_image.addDictionaryMember("name", JSON::makeString(iter2.first));
1117 QPDFObjectHandle image = iter2.second; 1128 QPDFObjectHandle image = iter2.second;
1118 QPDFObjectHandle dict = image.getDict(); 1129 QPDFObjectHandle dict = image.getDict();
1119 - j_image.addDictionaryMember("object", image.getJSON());  
1120 j_image.addDictionaryMember( 1130 j_image.addDictionaryMember(
1121 - "width", dict.getKey("/Width").getJSON()); 1131 + "object", image.getJSON(this->m->json_version));
  1132 + j_image.addDictionaryMember(
  1133 + "width", dict.getKey("/Width").getJSON(this->m->json_version));
1122 j_image.addDictionaryMember( 1134 j_image.addDictionaryMember(
1123 - "height", dict.getKey("/Height").getJSON()); 1135 + "height",
  1136 + dict.getKey("/Height").getJSON(this->m->json_version));
1124 j_image.addDictionaryMember( 1137 j_image.addDictionaryMember(
1125 - "colorspace", dict.getKey("/ColorSpace").getJSON()); 1138 + "colorspace",
  1139 + dict.getKey("/ColorSpace").getJSON(this->m->json_version));
1126 j_image.addDictionaryMember( 1140 j_image.addDictionaryMember(
1127 - "bitspercomponent", dict.getKey("/BitsPerComponent").getJSON()); 1141 + "bitspercomponent",
  1142 + dict.getKey("/BitsPerComponent")
  1143 + .getJSON(this->m->json_version));
1128 QPDFObjectHandle filters = dict.getKey("/Filter").wrapInArray(); 1144 QPDFObjectHandle filters = dict.getKey("/Filter").wrapInArray();
1129 - j_image.addDictionaryMember("filter", filters.getJSON()); 1145 + j_image.addDictionaryMember(
  1146 + "filter", filters.getJSON(this->m->json_version));
1130 QPDFObjectHandle decode_parms = dict.getKey("/DecodeParms"); 1147 QPDFObjectHandle decode_parms = dict.getKey("/DecodeParms");
1131 QPDFObjectHandle dp_array; 1148 QPDFObjectHandle dp_array;
1132 if (decode_parms.isArray()) { 1149 if (decode_parms.isArray()) {
@@ -1137,7 +1154,8 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1137,7 +1154,8 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1137 dp_array.appendItem(decode_parms); 1154 dp_array.appendItem(decode_parms);
1138 } 1155 }
1139 } 1156 }
1140 - j_image.addDictionaryMember("decodeparms", dp_array.getJSON()); 1157 + j_image.addDictionaryMember(
  1158 + "decodeparms", dp_array.getJSON(this->m->json_version));
1141 j_image.addDictionaryMember( 1159 j_image.addDictionaryMember(
1142 "filterable", 1160 "filterable",
1143 JSON::makeBool( 1161 JSON::makeBool(
@@ -1148,10 +1166,11 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1148,10 +1166,11 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1148 j_page.addDictionaryMember("contents", JSON::makeArray()); 1166 j_page.addDictionaryMember("contents", JSON::makeArray());
1149 std::vector<QPDFObjectHandle> content = ph.getPageContents(); 1167 std::vector<QPDFObjectHandle> content = ph.getPageContents();
1150 for (auto& iter2: content) { 1168 for (auto& iter2: content) {
1151 - j_contents.addArrayElement(iter2.getJSON()); 1169 + j_contents.addArrayElement(iter2.getJSON(this->m->json_version));
1152 } 1170 }
1153 j_page.addDictionaryMember( 1171 j_page.addDictionaryMember(
1154 - "label", pldh.getLabelForPage(pageno).getJSON()); 1172 + "label",
  1173 + pldh.getLabelForPage(pageno).getJSON(this->m->json_version));
1155 JSON j_outlines = 1174 JSON j_outlines =
1156 j_page.addDictionaryMember("outlines", JSON::makeArray()); 1175 j_page.addDictionaryMember("outlines", JSON::makeArray());
1157 std::vector<QPDFOutlineObjectHelper> outlines = 1176 std::vector<QPDFOutlineObjectHelper> outlines =
@@ -1159,11 +1178,12 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1159,11 +1178,12 @@ QPDFJob::doJSONPages(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1159 for (auto& oiter: outlines) { 1178 for (auto& oiter: outlines) {
1160 JSON j_outline = j_outlines.addArrayElement(JSON::makeDictionary()); 1179 JSON j_outline = j_outlines.addArrayElement(JSON::makeDictionary());
1161 j_outline.addDictionaryMember( 1180 j_outline.addDictionaryMember(
1162 - "object", oiter.getObjectHandle().getJSON()); 1181 + "object",
  1182 + oiter.getObjectHandle().getJSON(this->m->json_version));
1163 j_outline.addDictionaryMember( 1183 j_outline.addDictionaryMember(
1164 "title", JSON::makeString(oiter.getTitle())); 1184 "title", JSON::makeString(oiter.getTitle()));
1165 j_outline.addDictionaryMember( 1185 j_outline.addDictionaryMember(
1166 - "dest", oiter.getDest().getJSON(true)); 1186 + "dest", oiter.getDest().getJSON(this->m->json_version, true));
1167 } 1187 }
1168 j_page.addDictionaryMember("pageposfrom1", JSON::makeInt(1 + pageno)); 1188 j_page.addDictionaryMember("pageposfrom1", JSON::makeInt(1 + pageno));
1169 JSON::writeArrayItem(p, first_page, j_page, 1); 1189 JSON::writeArrayItem(p, first_page, j_page, 1);
@@ -1192,25 +1212,29 @@ QPDFJob::doJSONPageLabels(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1192,25 +1212,29 @@ QPDFJob::doJSONPageLabels(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1192 break; 1212 break;
1193 } 1213 }
1194 JSON j_label = j_labels.addArrayElement(JSON::makeDictionary()); 1214 JSON j_label = j_labels.addArrayElement(JSON::makeDictionary());
1195 - j_label.addDictionaryMember("index", (*iter).getJSON()); 1215 + j_label.addDictionaryMember(
  1216 + "index", (*iter).getJSON(this->m->json_version));
1196 ++iter; 1217 ++iter;
1197 - j_label.addDictionaryMember("label", (*iter).getJSON()); 1218 + j_label.addDictionaryMember(
  1219 + "label", (*iter).getJSON(this->m->json_version));
1198 } 1220 }
1199 } 1221 }
1200 JSON::writeDictionaryItem(p, first, "pagelabels", j_labels, 0); 1222 JSON::writeDictionaryItem(p, first, "pagelabels", j_labels, 0);
1201 } 1223 }
1202 1224
1203 -static void  
1204 -add_outlines_to_json( 1225 +void
  1226 +QPDFJob::addOutlinesToJson(
1205 std::vector<QPDFOutlineObjectHelper> outlines, 1227 std::vector<QPDFOutlineObjectHelper> outlines,
1206 JSON& j, 1228 JSON& j,
1207 std::map<QPDFObjGen, int>& page_numbers) 1229 std::map<QPDFObjGen, int>& page_numbers)
1208 { 1230 {
1209 for (auto& ol: outlines) { 1231 for (auto& ol: outlines) {
1210 JSON jo = j.addArrayElement(JSON::makeDictionary()); 1232 JSON jo = j.addArrayElement(JSON::makeDictionary());
1211 - jo.addDictionaryMember("object", ol.getObjectHandle().getJSON()); 1233 + jo.addDictionaryMember(
  1234 + "object", ol.getObjectHandle().getJSON(this->m->json_version));
1212 jo.addDictionaryMember("title", JSON::makeString(ol.getTitle())); 1235 jo.addDictionaryMember("title", JSON::makeString(ol.getTitle()));
1213 - jo.addDictionaryMember("dest", ol.getDest().getJSON(true)); 1236 + jo.addDictionaryMember(
  1237 + "dest", ol.getDest().getJSON(this->m->json_version, true));
1214 jo.addDictionaryMember("open", JSON::makeBool(ol.getCount() >= 0)); 1238 jo.addDictionaryMember("open", JSON::makeBool(ol.getCount() >= 0));
1215 QPDFObjectHandle page = ol.getDestPage(); 1239 QPDFObjectHandle page = ol.getDestPage();
1216 JSON j_destpage = JSON::makeNull(); 1240 JSON j_destpage = JSON::makeNull();
@@ -1222,7 +1246,7 @@ add_outlines_to_json( @@ -1222,7 +1246,7 @@ add_outlines_to_json(
1222 } 1246 }
1223 jo.addDictionaryMember("destpageposfrom1", j_destpage); 1247 jo.addDictionaryMember("destpageposfrom1", j_destpage);
1224 JSON j_kids = jo.addDictionaryMember("kids", JSON::makeArray()); 1248 JSON j_kids = jo.addDictionaryMember("kids", JSON::makeArray());
1225 - add_outlines_to_json(ol.getKids(), j_kids, page_numbers); 1249 + addOutlinesToJson(ol.getKids(), j_kids, page_numbers);
1226 } 1250 }
1227 } 1251 }
1228 1252
@@ -1240,7 +1264,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1240,7 +1264,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1240 1264
1241 JSON j_outlines = JSON::makeArray(); 1265 JSON j_outlines = JSON::makeArray();
1242 QPDFOutlineDocumentHelper odh(pdf); 1266 QPDFOutlineDocumentHelper odh(pdf);
1243 - add_outlines_to_json(odh.getTopLevelOutlines(), j_outlines, page_numbers); 1267 + addOutlinesToJson(odh.getTopLevelOutlines(), j_outlines, page_numbers);
1244 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 0); 1268 JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 0);
1245 } 1269 }
1246 1270
@@ -1265,9 +1289,11 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1265,9 +1289,11 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1265 QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(aoh); 1289 QPDFFormFieldObjectHelper ffh = afdh.getFieldForAnnotation(aoh);
1266 JSON j_field = j_fields.addArrayElement(JSON::makeDictionary()); 1290 JSON j_field = j_fields.addArrayElement(JSON::makeDictionary());
1267 j_field.addDictionaryMember( 1291 j_field.addDictionaryMember(
1268 - "object", ffh.getObjectHandle().getJSON()); 1292 + "object", ffh.getObjectHandle().getJSON(this->m->json_version));
1269 j_field.addDictionaryMember( 1293 j_field.addDictionaryMember(
1270 - "parent", ffh.getObjectHandle().getKey("/Parent").getJSON()); 1294 + "parent",
  1295 + ffh.getObjectHandle().getKey("/Parent").getJSON(
  1296 + this->m->json_version));
1271 j_field.addDictionaryMember( 1297 j_field.addDictionaryMember(
1272 "pageposfrom1", JSON::makeInt(pagepos1)); 1298 "pageposfrom1", JSON::makeInt(pagepos1));
1273 j_field.addDictionaryMember( 1299 j_field.addDictionaryMember(
@@ -1282,9 +1308,11 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1282,9 +1308,11 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1282 "alternativename", JSON::makeString(ffh.getAlternativeName())); 1308 "alternativename", JSON::makeString(ffh.getAlternativeName()));
1283 j_field.addDictionaryMember( 1309 j_field.addDictionaryMember(
1284 "mappingname", JSON::makeString(ffh.getMappingName())); 1310 "mappingname", JSON::makeString(ffh.getMappingName()));
1285 - j_field.addDictionaryMember("value", ffh.getValue().getJSON());  
1286 j_field.addDictionaryMember( 1311 j_field.addDictionaryMember(
1287 - "defaultvalue", ffh.getDefaultValue().getJSON()); 1312 + "value", ffh.getValue().getJSON(this->m->json_version));
  1313 + j_field.addDictionaryMember(
  1314 + "defaultvalue",
  1315 + ffh.getDefaultValue().getJSON(this->m->json_version));
1288 j_field.addDictionaryMember( 1316 j_field.addDictionaryMember(
1289 "quadding", JSON::makeInt(ffh.getQuadding())); 1317 "quadding", JSON::makeInt(ffh.getQuadding()));
1290 j_field.addDictionaryMember( 1318 j_field.addDictionaryMember(
@@ -1303,7 +1331,7 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf) @@ -1303,7 +1331,7 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool&amp; first, QPDF&amp; pdf)
1303 JSON j_annot = j_field.addDictionaryMember( 1331 JSON j_annot = j_field.addDictionaryMember(
1304 "annotation", JSON::makeDictionary()); 1332 "annotation", JSON::makeDictionary());
1305 j_annot.addDictionaryMember( 1333 j_annot.addDictionaryMember(
1306 - "object", aoh.getObjectHandle().getJSON()); 1334 + "object", aoh.getObjectHandle().getJSON(this->m->json_version));
1307 j_annot.addDictionaryMember( 1335 j_annot.addDictionaryMember(
1308 "appearancestate", JSON::makeString(aoh.getAppearanceState())); 1336 "appearancestate", JSON::makeString(aoh.getAppearanceState()));
1309 j_annot.addDictionaryMember( 1337 j_annot.addDictionaryMember(
@@ -1621,7 +1649,8 @@ QPDFJob::doJSON(QPDF&amp; pdf, Pipeline* p) @@ -1621,7 +1649,8 @@ QPDFJob::doJSON(QPDF&amp; pdf, Pipeline* p)
1621 // change is made to the JSON format. Clients of the JSON are to 1649 // change is made to the JSON format. Clients of the JSON are to
1622 // ignore unrecognized keys, so we only update the version of a 1650 // ignore unrecognized keys, so we only update the version of a
1623 // key disappears or if its value changes meaning. 1651 // key disappears or if its value changes meaning.
1624 - JSON::writeDictionaryItem(p, first, "version", JSON::makeInt(1), 0); 1652 + JSON::writeDictionaryItem(
  1653 + p, first, "version", JSON::makeInt(this->m->json_version), 0);
1625 JSON j_params = JSON::makeDictionary(); 1654 JSON j_params = JSON::makeDictionary();
1626 std::string decode_level_str; 1655 std::string decode_level_str;
1627 switch (m->decode_level) { 1656 switch (m->decode_level) {
libqpdf/QPDFJob_config.cc
@@ -235,11 +235,11 @@ QPDFJob::Config* @@ -235,11 +235,11 @@ QPDFJob::Config*
235 QPDFJob::Config::json(std::string const& parameter) 235 QPDFJob::Config::json(std::string const& parameter)
236 { 236 {
237 if (parameter.empty() || (parameter == "latest")) { 237 if (parameter.empty() || (parameter == "latest")) {
238 - o.m->json_version = 1; 238 + o.m->json_version = JSON::LATEST;
239 } else { 239 } else {
240 o.m->json_version = QUtil::string_to_int(parameter.c_str()); 240 o.m->json_version = QUtil::string_to_int(parameter.c_str());
241 } 241 }
242 - if (o.m->json_version != 1) { 242 + if ((o.m->json_version < 1) || (o.m->json_version > JSON::LATEST)) {
243 usage(std::string("unsupported json version ") + parameter); 243 usage(std::string("unsupported json version ") + parameter);
244 } 244 }
245 o.m->require_outfile = false; 245 o.m->require_outfile = false;
libqpdf/QPDFObjectHandle.cc
@@ -1775,9 +1775,16 @@ QPDFObjectHandle::unparseBinary() @@ -1775,9 +1775,16 @@ QPDFObjectHandle::unparseBinary()
1775 } 1775 }
1776 } 1776 }
1777 1777
  1778 +// Deprecated versionless getJSON to be removed in qpdf 12
1778 JSON 1779 JSON
1779 QPDFObjectHandle::getJSON(bool dereference_indirect) 1780 QPDFObjectHandle::getJSON(bool dereference_indirect)
1780 { 1781 {
  1782 + return getJSON(1, dereference_indirect);
  1783 +}
  1784 +
  1785 +JSON
  1786 +QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
  1787 +{
1781 if ((!dereference_indirect) && this->isIndirect()) { 1788 if ((!dereference_indirect) && this->isIndirect()) {
1782 return JSON::makeString(unparse()); 1789 return JSON::makeString(unparse());
1783 } else { 1790 } else {
@@ -1786,7 +1793,7 @@ QPDFObjectHandle::getJSON(bool dereference_indirect) @@ -1786,7 +1793,7 @@ QPDFObjectHandle::getJSON(bool dereference_indirect)
1786 throw std::logic_error( 1793 throw std::logic_error(
1787 "QPDFObjectHandle: attempting to unparse a reserved object"); 1794 "QPDFObjectHandle: attempting to unparse a reserved object");
1788 } 1795 }
1789 - return this->obj->getJSON(); 1796 + return this->obj->getJSON(json_version);
1790 } 1797 }
1791 } 1798 }
1792 1799
libqpdf/QPDF_Array.cc
@@ -34,12 +34,12 @@ QPDF_Array::unparse() @@ -34,12 +34,12 @@ QPDF_Array::unparse()
34 } 34 }
35 35
36 JSON 36 JSON
37 -QPDF_Array::getJSON() 37 +QPDF_Array::getJSON(int json_version)
38 { 38 {
39 JSON j = JSON::makeArray(); 39 JSON j = JSON::makeArray();
40 size_t size = this->elements.size(); 40 size_t size = this->elements.size();
41 for (size_t i = 0; i < size; ++i) { 41 for (size_t i = 0; i < size; ++i) {
42 - j.addArrayElement(this->elements.at(i).getJSON()); 42 + j.addArrayElement(this->elements.at(i).getJSON(json_version));
43 } 43 }
44 return j; 44 return j;
45 } 45 }
libqpdf/QPDF_Bool.cc
@@ -12,7 +12,7 @@ QPDF_Bool::unparse() @@ -12,7 +12,7 @@ QPDF_Bool::unparse()
12 } 12 }
13 13
14 JSON 14 JSON
15 -QPDF_Bool::getJSON() 15 +QPDF_Bool::getJSON(int json_version)
16 { 16 {
17 return JSON::makeBool(this->val); 17 return JSON::makeBool(this->val);
18 } 18 }
libqpdf/QPDF_Dictionary.cc
@@ -32,13 +32,14 @@ QPDF_Dictionary::unparse() @@ -32,13 +32,14 @@ QPDF_Dictionary::unparse()
32 } 32 }
33 33
34 JSON 34 JSON
35 -QPDF_Dictionary::getJSON() 35 +QPDF_Dictionary::getJSON(int json_version)
36 { 36 {
37 JSON j = JSON::makeDictionary(); 37 JSON j = JSON::makeDictionary();
38 for (auto& iter: this->items) { 38 for (auto& iter: this->items) {
39 if (!iter.second.isNull()) { 39 if (!iter.second.isNull()) {
40 j.addDictionaryMember( 40 j.addDictionaryMember(
41 - QPDF_Name::normalizeName(iter.first), iter.second.getJSON()); 41 + QPDF_Name::normalizeName(iter.first),
  42 + iter.second.getJSON(json_version));
42 } 43 }
43 } 44 }
44 return j; 45 return j;
libqpdf/QPDF_InlineImage.cc
@@ -14,7 +14,7 @@ QPDF_InlineImage::unparse() @@ -14,7 +14,7 @@ QPDF_InlineImage::unparse()
14 } 14 }
15 15
16 JSON 16 JSON
17 -QPDF_InlineImage::getJSON() 17 +QPDF_InlineImage::getJSON(int json_version)
18 { 18 {
19 return JSON::makeNull(); 19 return JSON::makeNull();
20 } 20 }
libqpdf/QPDF_Integer.cc
@@ -14,7 +14,7 @@ QPDF_Integer::unparse() @@ -14,7 +14,7 @@ QPDF_Integer::unparse()
14 } 14 }
15 15
16 JSON 16 JSON
17 -QPDF_Integer::getJSON() 17 +QPDF_Integer::getJSON(int json_version)
18 { 18 {
19 return JSON::makeInt(this->val); 19 return JSON::makeInt(this->val);
20 } 20 }
libqpdf/QPDF_Name.cc
@@ -40,7 +40,7 @@ QPDF_Name::unparse() @@ -40,7 +40,7 @@ QPDF_Name::unparse()
40 } 40 }
41 41
42 JSON 42 JSON
43 -QPDF_Name::getJSON() 43 +QPDF_Name::getJSON(int json_version)
44 { 44 {
45 return JSON::makeString(normalizeName(this->name)); 45 return JSON::makeString(normalizeName(this->name));
46 } 46 }
libqpdf/QPDF_Null.cc
@@ -7,7 +7,7 @@ QPDF_Null::unparse() @@ -7,7 +7,7 @@ QPDF_Null::unparse()
7 } 7 }
8 8
9 JSON 9 JSON
10 -QPDF_Null::getJSON() 10 +QPDF_Null::getJSON(int json_version)
11 { 11 {
12 return JSON::makeNull(); 12 return JSON::makeNull();
13 } 13 }
libqpdf/QPDF_Operator.cc
@@ -14,7 +14,7 @@ QPDF_Operator::unparse() @@ -14,7 +14,7 @@ QPDF_Operator::unparse()
14 } 14 }
15 15
16 JSON 16 JSON
17 -QPDF_Operator::getJSON() 17 +QPDF_Operator::getJSON(int json_version)
18 { 18 {
19 return JSON::makeNull(); 19 return JSON::makeNull();
20 } 20 }
libqpdf/QPDF_Real.cc
@@ -20,7 +20,7 @@ QPDF_Real::unparse() @@ -20,7 +20,7 @@ QPDF_Real::unparse()
20 } 20 }
21 21
22 JSON 22 JSON
23 -QPDF_Real::getJSON() 23 +QPDF_Real::getJSON(int json_version)
24 { 24 {
25 // While PDF allows .x or -.x, JSON does not. Rather than 25 // While PDF allows .x or -.x, JSON does not. Rather than
26 // converting from string to double and back, just handle this as a 26 // converting from string to double and back, just handle this as a
libqpdf/QPDF_Reserved.cc
@@ -10,7 +10,7 @@ QPDF_Reserved::unparse() @@ -10,7 +10,7 @@ QPDF_Reserved::unparse()
10 } 10 }
11 11
12 JSON 12 JSON
13 -QPDF_Reserved::getJSON() 13 +QPDF_Reserved::getJSON(int json_version)
14 { 14 {
15 throw std::logic_error("attempt to generate JSON from QPDF_Reserved"); 15 throw std::logic_error("attempt to generate JSON from QPDF_Reserved");
16 return JSON::makeNull(); 16 return JSON::makeNull();
libqpdf/QPDF_Stream.cc
@@ -151,9 +151,10 @@ QPDF_Stream::unparse() @@ -151,9 +151,10 @@ QPDF_Stream::unparse()
151 } 151 }
152 152
153 JSON 153 JSON
154 -QPDF_Stream::getJSON() 154 +QPDF_Stream::getJSON(int json_version)
155 { 155 {
156 - return this->stream_dict.getJSON(); 156 + // QXXXQ
  157 + return this->stream_dict.getJSON(json_version);
157 } 158 }
158 159
159 QPDFObject::object_type_e 160 QPDFObject::object_type_e
libqpdf/QPDF_String.cc
@@ -43,8 +43,9 @@ QPDF_String::unparse() @@ -43,8 +43,9 @@ QPDF_String::unparse()
43 } 43 }
44 44
45 JSON 45 JSON
46 -QPDF_String::getJSON() 46 +QPDF_String::getJSON(int json_version)
47 { 47 {
  48 + // QXXXQ
48 return JSON::makeString(getUTF8Val()); 49 return JSON::makeString(getUTF8Val());
49 } 50 }
50 51
libqpdf/qpdf/QPDF_Array.hh
@@ -14,7 +14,7 @@ class QPDF_Array: public QPDFObject @@ -14,7 +14,7 @@ class QPDF_Array: public QPDFObject
14 QPDF_Array(SparseOHArray const& items); 14 QPDF_Array(SparseOHArray const& items);
15 virtual ~QPDF_Array() = default; 15 virtual ~QPDF_Array() = default;
16 virtual std::string unparse(); 16 virtual std::string unparse();
17 - virtual JSON getJSON(); 17 + virtual JSON getJSON(int json_version);
18 virtual QPDFObject::object_type_e getTypeCode() const; 18 virtual QPDFObject::object_type_e getTypeCode() const;
19 virtual char const* getTypeName() const; 19 virtual char const* getTypeName() const;
20 virtual void setDescription(QPDF*, std::string const&); 20 virtual void setDescription(QPDF*, std::string const&);
libqpdf/qpdf/QPDF_Bool.hh
@@ -9,7 +9,7 @@ class QPDF_Bool: public QPDFObject @@ -9,7 +9,7 @@ class QPDF_Bool: public QPDFObject
9 QPDF_Bool(bool val); 9 QPDF_Bool(bool val);
10 virtual ~QPDF_Bool() = default; 10 virtual ~QPDF_Bool() = default;
11 virtual std::string unparse(); 11 virtual std::string unparse();
12 - virtual JSON getJSON(); 12 + virtual JSON getJSON(int json_version);
13 virtual QPDFObject::object_type_e getTypeCode() const; 13 virtual QPDFObject::object_type_e getTypeCode() const;
14 virtual char const* getTypeName() const; 14 virtual char const* getTypeName() const;
15 bool getVal() const; 15 bool getVal() const;
libqpdf/qpdf/QPDF_Dictionary.hh
@@ -14,7 +14,7 @@ class QPDF_Dictionary: public QPDFObject @@ -14,7 +14,7 @@ class QPDF_Dictionary: public QPDFObject
14 QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items); 14 QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items);
15 virtual ~QPDF_Dictionary() = default; 15 virtual ~QPDF_Dictionary() = default;
16 virtual std::string unparse(); 16 virtual std::string unparse();
17 - virtual JSON getJSON(); 17 + virtual JSON getJSON(int json_version);
18 virtual QPDFObject::object_type_e getTypeCode() const; 18 virtual QPDFObject::object_type_e getTypeCode() const;
19 virtual char const* getTypeName() const; 19 virtual char const* getTypeName() const;
20 virtual void setDescription(QPDF*, std::string const&); 20 virtual void setDescription(QPDF*, std::string const&);
libqpdf/qpdf/QPDF_InlineImage.hh
@@ -9,7 +9,7 @@ class QPDF_InlineImage: public QPDFObject @@ -9,7 +9,7 @@ class QPDF_InlineImage: public QPDFObject
9 QPDF_InlineImage(std::string const& val); 9 QPDF_InlineImage(std::string const& val);
10 virtual ~QPDF_InlineImage() = default; 10 virtual ~QPDF_InlineImage() = default;
11 virtual std::string unparse(); 11 virtual std::string unparse();
12 - virtual JSON getJSON(); 12 + virtual JSON getJSON(int json_version);
13 virtual QPDFObject::object_type_e getTypeCode() const; 13 virtual QPDFObject::object_type_e getTypeCode() const;
14 virtual char const* getTypeName() const; 14 virtual char const* getTypeName() const;
15 std::string getVal() const; 15 std::string getVal() const;
libqpdf/qpdf/QPDF_Integer.hh
@@ -9,7 +9,7 @@ class QPDF_Integer: public QPDFObject @@ -9,7 +9,7 @@ class QPDF_Integer: public QPDFObject
9 QPDF_Integer(long long val); 9 QPDF_Integer(long long val);
10 virtual ~QPDF_Integer() = default; 10 virtual ~QPDF_Integer() = default;
11 virtual std::string unparse(); 11 virtual std::string unparse();
12 - virtual JSON getJSON(); 12 + virtual JSON getJSON(int json_version);
13 virtual QPDFObject::object_type_e getTypeCode() const; 13 virtual QPDFObject::object_type_e getTypeCode() const;
14 virtual char const* getTypeName() const; 14 virtual char const* getTypeName() const;
15 long long getVal() const; 15 long long getVal() const;
libqpdf/qpdf/QPDF_Name.hh
@@ -9,7 +9,7 @@ class QPDF_Name: public QPDFObject @@ -9,7 +9,7 @@ class QPDF_Name: public QPDFObject
9 QPDF_Name(std::string const& name); 9 QPDF_Name(std::string const& name);
10 virtual ~QPDF_Name() = default; 10 virtual ~QPDF_Name() = default;
11 virtual std::string unparse(); 11 virtual std::string unparse();
12 - virtual JSON getJSON(); 12 + virtual JSON getJSON(int json_version);
13 virtual QPDFObject::object_type_e getTypeCode() const; 13 virtual QPDFObject::object_type_e getTypeCode() const;
14 virtual char const* getTypeName() const; 14 virtual char const* getTypeName() const;
15 std::string getName() const; 15 std::string getName() const;
libqpdf/qpdf/QPDF_Null.hh
@@ -8,7 +8,7 @@ class QPDF_Null: public QPDFObject @@ -8,7 +8,7 @@ class QPDF_Null: public QPDFObject
8 public: 8 public:
9 virtual ~QPDF_Null() = default; 9 virtual ~QPDF_Null() = default;
10 virtual std::string unparse(); 10 virtual std::string unparse();
11 - virtual JSON getJSON(); 11 + virtual JSON getJSON(int json_version);
12 virtual QPDFObject::object_type_e getTypeCode() const; 12 virtual QPDFObject::object_type_e getTypeCode() const;
13 virtual char const* getTypeName() const; 13 virtual char const* getTypeName() const;
14 }; 14 };
libqpdf/qpdf/QPDF_Operator.hh
@@ -9,7 +9,7 @@ class QPDF_Operator: public QPDFObject @@ -9,7 +9,7 @@ class QPDF_Operator: public QPDFObject
9 QPDF_Operator(std::string const& val); 9 QPDF_Operator(std::string const& val);
10 virtual ~QPDF_Operator() = default; 10 virtual ~QPDF_Operator() = default;
11 virtual std::string unparse(); 11 virtual std::string unparse();
12 - virtual JSON getJSON(); 12 + virtual JSON getJSON(int json_version);
13 virtual QPDFObject::object_type_e getTypeCode() const; 13 virtual QPDFObject::object_type_e getTypeCode() const;
14 virtual char const* getTypeName() const; 14 virtual char const* getTypeName() const;
15 std::string getVal() const; 15 std::string getVal() const;
libqpdf/qpdf/QPDF_Real.hh
@@ -10,7 +10,7 @@ class QPDF_Real: public QPDFObject @@ -10,7 +10,7 @@ class QPDF_Real: public QPDFObject
10 QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes); 10 QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes);
11 virtual ~QPDF_Real() = default; 11 virtual ~QPDF_Real() = default;
12 virtual std::string unparse(); 12 virtual std::string unparse();
13 - virtual JSON getJSON(); 13 + virtual JSON getJSON(int json_version);
14 virtual QPDFObject::object_type_e getTypeCode() const; 14 virtual QPDFObject::object_type_e getTypeCode() const;
15 virtual char const* getTypeName() const; 15 virtual char const* getTypeName() const;
16 std::string getVal(); 16 std::string getVal();
libqpdf/qpdf/QPDF_Reserved.hh
@@ -8,7 +8,7 @@ class QPDF_Reserved: public QPDFObject @@ -8,7 +8,7 @@ class QPDF_Reserved: public QPDFObject
8 public: 8 public:
9 virtual ~QPDF_Reserved() = default; 9 virtual ~QPDF_Reserved() = default;
10 virtual std::string unparse(); 10 virtual std::string unparse();
11 - virtual JSON getJSON(); 11 + virtual JSON getJSON(int json_version);
12 virtual QPDFObject::object_type_e getTypeCode() const; 12 virtual QPDFObject::object_type_e getTypeCode() const;
13 virtual char const* getTypeName() const; 13 virtual char const* getTypeName() const;
14 }; 14 };
libqpdf/qpdf/QPDF_Stream.hh
@@ -25,7 +25,7 @@ class QPDF_Stream: public QPDFObject @@ -25,7 +25,7 @@ class QPDF_Stream: public QPDFObject
25 size_t length); 25 size_t length);
26 virtual ~QPDF_Stream() = default; 26 virtual ~QPDF_Stream() = default;
27 virtual std::string unparse(); 27 virtual std::string unparse();
28 - virtual JSON getJSON(); 28 + virtual JSON getJSON(int json_version);
29 virtual QPDFObject::object_type_e getTypeCode() const; 29 virtual QPDFObject::object_type_e getTypeCode() const;
30 virtual char const* getTypeName() const; 30 virtual char const* getTypeName() const;
31 virtual void setDescription(QPDF*, std::string const&); 31 virtual void setDescription(QPDF*, std::string const&);
libqpdf/qpdf/QPDF_String.hh
@@ -15,7 +15,7 @@ class QPDF_String: public QPDFObject @@ -15,7 +15,7 @@ class QPDF_String: public QPDFObject
15 virtual QPDFObject::object_type_e getTypeCode() const; 15 virtual QPDFObject::object_type_e getTypeCode() const;
16 virtual char const* getTypeName() const; 16 virtual char const* getTypeName() const;
17 std::string unparse(bool force_binary); 17 std::string unparse(bool force_binary);
18 - virtual JSON getJSON(); 18 + virtual JSON getJSON(int json_version);
19 std::string getVal() const; 19 std::string getVal() const;
20 std::string getUTF8Val() const; 20 std::string getUTF8Val() const;
21 21
libqpdf/qpdf/auto_job_init.hh
@@ -19,7 +19,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized @@ -19,7 +19,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized
19 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; 19 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0};
20 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; 20 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0};
21 static char const* flatten_choices[] = {"all", "print", "screen", 0}; 21 static char const* flatten_choices[] = {"all", "print", "screen", 0};
22 -static char const* json_version_choices[] = {"1", "latest", 0}; 22 +static char const* json_version_choices[] = {"1", "2", "latest", 0};
23 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; 23 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0};
24 static char const* print128_choices[] = {"full", "low", "none", 0}; 24 static char const* print128_choices[] = {"full", "low", "none", 0};
25 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; 25 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
libqpdf/qpdf/auto_job_json_init.hh
@@ -12,7 +12,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized @@ -12,7 +12,7 @@ static char const* decode_level_choices[] = {&quot;none&quot;, &quot;generalized&quot;, &quot;specialized
12 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0}; 12 static char const* object_streams_choices[] = {"disable", "preserve", "generate", 0};
13 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0}; 13 static char const* remove_unref_choices[] = {"auto", "yes", "no", 0};
14 static char const* flatten_choices[] = {"all", "print", "screen", 0}; 14 static char const* flatten_choices[] = {"all", "print", "screen", 0};
15 -static char const* json_version_choices[] = {"1", "latest", 0}; 15 +static char const* json_version_choices[] = {"1", "2", "latest", 0};
16 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0}; 16 static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "objectinfo", "objects", "outlines", "pagelabels", "pages", 0};
17 static char const* print128_choices[] = {"full", "low", "none", 0}; 17 static char const* print128_choices[] = {"full", "low", "none", 0};
18 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0}; 18 static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
libtests/json.cc
@@ -100,10 +100,12 @@ test_main() @@ -100,10 +100,12 @@ test_main()
100 " ],\n" 100 " ],\n"
101 " \"yes\": false\n" 101 " \"yes\": false\n"
102 "}"); 102 "}");
103 - check(QPDFObjectHandle::newReal("0.12").getJSON(), "0.12");  
104 - check(QPDFObjectHandle::newReal(".34").getJSON(), "0.34");  
105 - check(QPDFObjectHandle::newReal("-0.56").getJSON(), "-0.56");  
106 - check(QPDFObjectHandle::newReal("-.78").getJSON(), "-0.78"); 103 + for (int i = 1; i <= JSON::LATEST; ++i) {
  104 + check(QPDFObjectHandle::newReal("0.12").getJSON(i), "0.12");
  105 + check(QPDFObjectHandle::newReal(".34").getJSON(i), "0.34");
  106 + check(QPDFObjectHandle::newReal("-0.56").getJSON(i), "-0.56");
  107 + check(QPDFObjectHandle::newReal("-.78").getJSON(i), "-0.78");
  108 + }
107 JSON jmap2 = JSON::parse(R"({"a": 1, "b": "two", "c": [true]})"); 109 JSON jmap2 = JSON::parse(R"({"a": 1, "b": "two", "c": [true]})");
108 std::map<std::string, std::string> dvalue; 110 std::map<std::string, std::string> dvalue;
109 assert(jmap2.forEachDictItem( 111 assert(jmap2.forEachDictItem(
qpdf/qtest/qpdf.test
@@ -4279,7 +4279,7 @@ foreach my $d (@encrypted_files) @@ -4279,7 +4279,7 @@ foreach my $d (@encrypted_files)
4279 my $enc_details = ""; 4279 my $enc_details = "";
4280 my $enc_json = 4280 my $enc_json =
4281 "{\n" . 4281 "{\n" .
4282 - " \"version\": 1,\n" . 4282 + " \"version\": 2,\n" .
4283 " \"parameters\": {\n" . 4283 " \"parameters\": {\n" .
4284 " \"decodelevel\": \"generalized\"\n" . 4284 " \"decodelevel\": \"generalized\"\n" .
4285 " },\n" . 4285 " },\n" .
qpdf/qtest/qpdf/direct-pages-json-objects.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/direct-pages-json-pages.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-defaults-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-image-streams-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-inline-images-all-size-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-inline-images-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-inline-images-keep-all-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-inline-images-keep-some-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-min-area-all-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-min-area-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-min-height-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-min-width-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/optimize-images-unsupported-json.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/page_api_2-json-objects.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/qtest/qpdf/page_api_2-json-pages.out
1 { 1 {
2 - "version": 1, 2 + "version": 2,
3 "parameters": { 3 "parameters": {
4 "decodelevel": "generalized" 4 "decodelevel": "generalized"
5 }, 5 },
qpdf/test_driver.cc
@@ -1922,7 +1922,7 @@ test_50(QPDF&amp; pdf, char const* arg2) @@ -1922,7 +1922,7 @@ test_50(QPDF&amp; pdf, char const* arg2)
1922 QPDFObjectHandle d1 = pdf.getTrailer().getKey("/Dict1"); 1922 QPDFObjectHandle d1 = pdf.getTrailer().getKey("/Dict1");
1923 QPDFObjectHandle d2 = pdf.getTrailer().getKey("/Dict2"); 1923 QPDFObjectHandle d2 = pdf.getTrailer().getKey("/Dict2");
1924 d1.mergeResources(d2); 1924 d1.mergeResources(d2);
1925 - std::cout << d1.getJSON().unparse() << std::endl; 1925 + std::cout << d1.getJSON(JSON::LATEST).unparse() << std::endl;
1926 // Top-level type mismatch 1926 // Top-level type mismatch
1927 d1.mergeResources(d2.getKey("/k1")); 1927 d1.mergeResources(d2.getKey("/k1"));
1928 for (auto const& name: d1.getResourceNames()) { 1928 for (auto const& name: d1.getResourceNames()) {
@@ -3114,7 +3114,7 @@ test_87(QPDF&amp; pdf, char const* arg2) @@ -3114,7 +3114,7 @@ test_87(QPDF&amp; pdf, char const* arg2)
3114 }); 3114 });
3115 assert(dict.unparse() == "<< /A 2 >>"); 3115 assert(dict.unparse() == "<< /A 2 >>");
3116 assert(dict.getKeys() == std::set<std::string>({"/A"})); 3116 assert(dict.getKeys() == std::set<std::string>({"/A"}));
3117 - assert(dict.getJSON().unparse() == "{\n \"/A\": 2\n}"); 3117 + assert(dict.getJSON(JSON::LATEST).unparse() == "{\n \"/A\": 2\n}");
3118 } 3118 }
3119 3119
3120 static void 3120 static void