Commit 0e3d4cdc9753ae59d42ff8478b0769196899032b
1 parent
8ad39a6c
Fix/clarify meaning of depth parameter to json write methods
Showing
4 changed files
with
58 additions
and
41 deletions
include/qpdf/JSON.hh
| @@ -65,16 +65,26 @@ class JSON | @@ -65,16 +65,26 @@ class JSON | ||
| 65 | QPDF_DLL | 65 | QPDF_DLL |
| 66 | void write(Pipeline*, size_t depth = 0) const; | 66 | void write(Pipeline*, size_t depth = 0) const; |
| 67 | 67 | ||
| 68 | - // Helper methods for writing JSON incrementally. Several methods | ||
| 69 | - // take a `bool& first` parameter. The open methods always set it | ||
| 70 | - // to true, and the methods to output items always set it to | ||
| 71 | - // false. This way, the item and close methods can always know | ||
| 72 | - // whether or not a first item is being written. The intended mode | ||
| 73 | - // of operation is to start with `bool first = true` (though it | ||
| 74 | - // doesn't matter how it's initialized) and just pass the same | ||
| 75 | - // `first` through to all the methods, letting the JSON object use | ||
| 76 | - // it to keep track of when it's writing a first object and when | ||
| 77 | - // it's not. | 68 | + // Helper methods for writing JSON incrementally. |
| 69 | + // | ||
| 70 | + // "first" -- Several methods take a `bool& first` parameter. The | ||
| 71 | + // open methods always set it to true, and the methods to output | ||
| 72 | + // items always set it to false. This way, the item and close | ||
| 73 | + // methods can always know whether or not a first item is being | ||
| 74 | + // written. The intended mode of operation is to start with a new | ||
| 75 | + // `bool first = true` each time a new container is opened and | ||
| 76 | + // to pass that `first` through to all the methods that are | ||
| 77 | + // called to add top-level items to the container as well as to | ||
| 78 | + // close the container. This lets the JSON object use it to keep | ||
| 79 | + // track of when it's writing a first object and when it's not. If | ||
| 80 | + // incrementally writing multiple levels of depth, a new `first` | ||
| 81 | + // should used for each new container that is opened. | ||
| 82 | + // | ||
| 83 | + // "depth" -- Indicate the level of depth. This is used for | ||
| 84 | + // consistent indentation. When writing incrementally, whenever | ||
| 85 | + // you call a method to add an item to a container, the value of | ||
| 86 | + // `depth` should be one more than whatever value is passed to the | ||
| 87 | + // container open and close methods. | ||
| 78 | 88 | ||
| 79 | // Open methods ignore the value of first and set it to false | 89 | // Open methods ignore the value of first and set it to false |
| 80 | QPDF_DLL | 90 | QPDF_DLL |
| @@ -106,9 +116,12 @@ class JSON | @@ -106,9 +116,12 @@ class JSON | ||
| 106 | Pipeline*, bool& first, JSON const& element, size_t depth = 0); | 116 | Pipeline*, bool& first, JSON const& element, size_t depth = 0); |
| 107 | // If writing nested structures incrementally, call writeNext | 117 | // If writing nested structures incrementally, call writeNext |
| 108 | // before opening a new array or container in the midst of an | 118 | // before opening a new array or container in the midst of an |
| 109 | - // existing one. The first you pass to writeNext should be the one | ||
| 110 | - // for the parent object. Then start a new first for the nested | ||
| 111 | - // item. | 119 | + // existing one. The `first` you pass to writeNext should be the |
| 120 | + // one for the parent object. The depth should be the one for the | ||
| 121 | + // child object. Then start a new `first` for the nested item. | ||
| 122 | + // Note that writeDictionaryKey and writeArrayItem call writeNext | ||
| 123 | + // for you, so this is most important when writing subsequent | ||
| 124 | + // items or container openers to an array. | ||
| 112 | QPDF_DLL | 125 | QPDF_DLL |
| 113 | static void writeNext(Pipeline* p, bool& first, size_t depth = 0); | 126 | static void writeNext(Pipeline* p, bool& first, size_t depth = 0); |
| 114 | 127 |
libqpdf/JSON.cc
| @@ -56,7 +56,7 @@ JSON::writeNext(Pipeline* p, bool& first, size_t depth) | @@ -56,7 +56,7 @@ JSON::writeNext(Pipeline* p, bool& first, size_t depth) | ||
| 56 | *p << ","; | 56 | *p << ","; |
| 57 | } | 57 | } |
| 58 | *p << "\n"; | 58 | *p << "\n"; |
| 59 | - writeIndent(p, 1 + depth); | 59 | + writeIndent(p, depth); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | void | 62 | void |
| @@ -102,7 +102,7 @@ JSON::writeDictionaryItem( | @@ -102,7 +102,7 @@ JSON::writeDictionaryItem( | ||
| 102 | size_t depth) | 102 | size_t depth) |
| 103 | { | 103 | { |
| 104 | writeDictionaryKey(p, first, key, depth); | 104 | writeDictionaryKey(p, first, key, depth); |
| 105 | - value.write(p, 1 + depth); | 105 | + value.write(p, depth); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | void | 108 | void |
| @@ -110,7 +110,7 @@ JSON::writeArrayItem( | @@ -110,7 +110,7 @@ JSON::writeArrayItem( | ||
| 110 | Pipeline* p, bool& first, JSON const& element, size_t depth) | 110 | Pipeline* p, bool& first, JSON const& element, size_t depth) |
| 111 | { | 111 | { |
| 112 | writeNext(p, first, depth); | 112 | writeNext(p, first, depth); |
| 113 | - element.write(p, 1 + depth); | 113 | + element.write(p, depth); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | void | 116 | void |
| @@ -119,7 +119,7 @@ JSON::JSON_dictionary::write(Pipeline* p, size_t depth) const | @@ -119,7 +119,7 @@ JSON::JSON_dictionary::write(Pipeline* p, size_t depth) const | ||
| 119 | bool first = true; | 119 | bool first = true; |
| 120 | writeDictionaryOpen(p, first, depth); | 120 | writeDictionaryOpen(p, first, depth); |
| 121 | for (auto const& iter: members) { | 121 | for (auto const& iter: members) { |
| 122 | - writeDictionaryItem(p, first, iter.first, iter.second, depth); | 122 | + writeDictionaryItem(p, first, iter.first, iter.second, 1 + depth); |
| 123 | } | 123 | } |
| 124 | writeDictionaryClose(p, first, depth); | 124 | writeDictionaryClose(p, first, depth); |
| 125 | } | 125 | } |
| @@ -130,7 +130,7 @@ JSON::JSON_array::write(Pipeline* p, size_t depth) const | @@ -130,7 +130,7 @@ JSON::JSON_array::write(Pipeline* p, size_t depth) const | ||
| 130 | bool first = true; | 130 | bool first = true; |
| 131 | writeArrayOpen(p, first, depth); | 131 | writeArrayOpen(p, first, depth); |
| 132 | for (auto const& element: elements) { | 132 | for (auto const& element: elements) { |
| 133 | - writeArrayItem(p, first, element, depth); | 133 | + writeArrayItem(p, first, element, 1 + depth); |
| 134 | } | 134 | } |
| 135 | writeArrayClose(p, first, depth); | 135 | writeArrayClose(p, first, depth); |
| 136 | } | 136 | } |
libqpdf/QPDFJob.cc
| @@ -1082,7 +1082,7 @@ QPDFJob::doJSONObject( | @@ -1082,7 +1082,7 @@ QPDFJob::doJSONObject( | ||
| 1082 | Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle& obj) | 1082 | Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle& obj) |
| 1083 | { | 1083 | { |
| 1084 | if (this->m->json_version == 1) { | 1084 | if (this->m->json_version == 1) { |
| 1085 | - JSON::writeDictionaryItem(p, first, key, obj.getJSON(1, true), 1); | 1085 | + JSON::writeDictionaryItem(p, first, key, obj.getJSON(1, true), 2); |
| 1086 | } else { | 1086 | } else { |
| 1087 | auto j = JSON::makeDictionary(); | 1087 | auto j = JSON::makeDictionary(); |
| 1088 | if (obj.isStream()) { | 1088 | if (obj.isStream()) { |
| @@ -1093,14 +1093,14 @@ QPDFJob::doJSONObject( | @@ -1093,14 +1093,14 @@ QPDFJob::doJSONObject( | ||
| 1093 | j.addDictionaryMember( | 1093 | j.addDictionaryMember( |
| 1094 | "value", obj.getJSON(this->m->json_version, true)); | 1094 | "value", obj.getJSON(this->m->json_version, true)); |
| 1095 | } | 1095 | } |
| 1096 | - JSON::writeDictionaryItem(p, first, key, j, 1); | 1096 | + JSON::writeDictionaryItem(p, first, key, j, 2); |
| 1097 | } | 1097 | } |
| 1098 | } | 1098 | } |
| 1099 | 1099 | ||
| 1100 | void | 1100 | void |
| 1101 | QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) | 1101 | QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) |
| 1102 | { | 1102 | { |
| 1103 | - JSON::writeDictionaryKey(p, first, "objects", 0); | 1103 | + JSON::writeDictionaryKey(p, first, "objects", 1); |
| 1104 | bool first_object = true; | 1104 | bool first_object = true; |
| 1105 | JSON::writeDictionaryOpen(p, first_object, 1); | 1105 | JSON::writeDictionaryOpen(p, first_object, 1); |
| 1106 | bool all_objects = m->json_objects.empty(); | 1106 | bool all_objects = m->json_objects.empty(); |
| @@ -1124,7 +1124,7 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) | @@ -1124,7 +1124,7 @@ QPDFJob::doJSONObjects(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1124 | void | 1124 | void |
| 1125 | QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) | 1125 | QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) |
| 1126 | { | 1126 | { |
| 1127 | - JSON::writeDictionaryKey(p, first, "objectinfo", 0); | 1127 | + JSON::writeDictionaryKey(p, first, "objectinfo", 1); |
| 1128 | bool first_object = true; | 1128 | bool first_object = true; |
| 1129 | JSON::writeDictionaryOpen(p, first_object, 1); | 1129 | JSON::writeDictionaryOpen(p, first_object, 1); |
| 1130 | bool all_objects = m->json_objects.empty(); | 1130 | bool all_objects = m->json_objects.empty(); |
| @@ -1147,7 +1147,7 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) | @@ -1147,7 +1147,7 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1147 | this->m->json_version, true) | 1147 | this->m->json_version, true) |
| 1148 | : JSON::makeNull())); | 1148 | : JSON::makeNull())); |
| 1149 | JSON::writeDictionaryItem( | 1149 | JSON::writeDictionaryItem( |
| 1150 | - p, first_object, obj.unparse(), j_details, 1); | 1150 | + p, first_object, obj.unparse(), j_details, 2); |
| 1151 | } | 1151 | } |
| 1152 | } | 1152 | } |
| 1153 | JSON::writeDictionaryClose(p, first_object, 1); | 1153 | JSON::writeDictionaryClose(p, first_object, 1); |
| @@ -1156,9 +1156,9 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) | @@ -1156,9 +1156,9 @@ QPDFJob::doJSONObjectinfo(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1156 | void | 1156 | void |
| 1157 | QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | 1157 | QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) |
| 1158 | { | 1158 | { |
| 1159 | - JSON::writeDictionaryKey(p, first, "pages", 0); | 1159 | + JSON::writeDictionaryKey(p, first, "pages", 1); |
| 1160 | bool first_page = true; | 1160 | bool first_page = true; |
| 1161 | - JSON::writeArrayOpen(p, first_page, 1); | 1161 | + JSON::writeArrayOpen(p, first_page, 2); |
| 1162 | QPDFPageLabelDocumentHelper pldh(pdf); | 1162 | QPDFPageLabelDocumentHelper pldh(pdf); |
| 1163 | QPDFOutlineDocumentHelper odh(pdf); | 1163 | QPDFOutlineDocumentHelper odh(pdf); |
| 1164 | int pageno = -1; | 1164 | int pageno = -1; |
| @@ -1232,7 +1232,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | @@ -1232,7 +1232,7 @@ QPDFJob::doJSONPages(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1232 | "dest", oiter.getDest().getJSON(this->m->json_version, true)); | 1232 | "dest", oiter.getDest().getJSON(this->m->json_version, true)); |
| 1233 | } | 1233 | } |
| 1234 | j_page.addDictionaryMember("pageposfrom1", JSON::makeInt(1 + pageno)); | 1234 | j_page.addDictionaryMember("pageposfrom1", JSON::makeInt(1 + pageno)); |
| 1235 | - JSON::writeArrayItem(p, first_page, j_page, 1); | 1235 | + JSON::writeArrayItem(p, first_page, j_page, 2); |
| 1236 | } | 1236 | } |
| 1237 | JSON::writeArrayClose(p, first_page, 1); | 1237 | JSON::writeArrayClose(p, first_page, 1); |
| 1238 | } | 1238 | } |
| @@ -1262,7 +1262,7 @@ QPDFJob::doJSONPageLabels(Pipeline* p, bool& first, QPDF& pdf) | @@ -1262,7 +1262,7 @@ QPDFJob::doJSONPageLabels(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1262 | "label", (*iter).getJSON(this->m->json_version)); | 1262 | "label", (*iter).getJSON(this->m->json_version)); |
| 1263 | } | 1263 | } |
| 1264 | } | 1264 | } |
| 1265 | - JSON::writeDictionaryItem(p, first, "pagelabels", j_labels, 0); | 1265 | + JSON::writeDictionaryItem(p, first, "pagelabels", j_labels, 1); |
| 1266 | } | 1266 | } |
| 1267 | 1267 | ||
| 1268 | void | 1268 | void |
| @@ -1306,7 +1306,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool& first, QPDF& pdf) | @@ -1306,7 +1306,7 @@ QPDFJob::doJSONOutlines(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1306 | JSON j_outlines = JSON::makeArray(); | 1306 | JSON j_outlines = JSON::makeArray(); |
| 1307 | QPDFOutlineDocumentHelper odh(pdf); | 1307 | QPDFOutlineDocumentHelper odh(pdf); |
| 1308 | addOutlinesToJson(odh.getTopLevelOutlines(), j_outlines, page_numbers); | 1308 | addOutlinesToJson(odh.getTopLevelOutlines(), j_outlines, page_numbers); |
| 1309 | - JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 0); | 1309 | + JSON::writeDictionaryItem(p, first, "outlines", j_outlines, 1); |
| 1310 | } | 1310 | } |
| 1311 | 1311 | ||
| 1312 | void | 1312 | void |
| @@ -1374,7 +1374,7 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf) | @@ -1374,7 +1374,7 @@ QPDFJob::doJSONAcroform(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1374 | "annotationflags", JSON::makeInt(aoh.getFlags())); | 1374 | "annotationflags", JSON::makeInt(aoh.getFlags())); |
| 1375 | } | 1375 | } |
| 1376 | } | 1376 | } |
| 1377 | - JSON::writeDictionaryItem(p, first, "acroform", j_acroform, 0); | 1377 | + JSON::writeDictionaryItem(p, first, "acroform", j_acroform, 1); |
| 1378 | } | 1378 | } |
| 1379 | 1379 | ||
| 1380 | void | 1380 | void |
| @@ -1470,7 +1470,7 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf) | @@ -1470,7 +1470,7 @@ QPDFJob::doJSONEncrypt(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1470 | "stringmethod", JSON::makeString(s_string_method)); | 1470 | "stringmethod", JSON::makeString(s_string_method)); |
| 1471 | j_parameters.addDictionaryMember( | 1471 | j_parameters.addDictionaryMember( |
| 1472 | "filemethod", JSON::makeString(s_file_method)); | 1472 | "filemethod", JSON::makeString(s_file_method)); |
| 1473 | - JSON::writeDictionaryItem(p, first, "encrypt", j_encrypt, 0); | 1473 | + JSON::writeDictionaryItem(p, first, "encrypt", j_encrypt, 1); |
| 1474 | } | 1474 | } |
| 1475 | 1475 | ||
| 1476 | void | 1476 | void |
| @@ -1532,7 +1532,7 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) | @@ -1532,7 +1532,7 @@ QPDFJob::doJSONAttachments(Pipeline* p, bool& first, QPDF& pdf) | ||
| 1532 | null_or_string(QUtil::hex_encode(efs.getChecksum()))); | 1532 | null_or_string(QUtil::hex_encode(efs.getChecksum()))); |
| 1533 | } | 1533 | } |
| 1534 | } | 1534 | } |
| 1535 | - JSON::writeDictionaryItem(p, first, "attachments", j_attachments, 0); | 1535 | + JSON::writeDictionaryItem(p, first, "attachments", j_attachments, 1); |
| 1536 | } | 1536 | } |
| 1537 | 1537 | ||
| 1538 | JSON | 1538 | JSON |
| @@ -1755,7 +1755,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | @@ -1755,7 +1755,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | ||
| 1755 | // ignore unrecognized keys, so we only update the version of a | 1755 | // ignore unrecognized keys, so we only update the version of a |
| 1756 | // key disappears or if its value changes meaning. | 1756 | // key disappears or if its value changes meaning. |
| 1757 | JSON::writeDictionaryItem( | 1757 | JSON::writeDictionaryItem( |
| 1758 | - p, first, "version", JSON::makeInt(this->m->json_version), 0); | 1758 | + p, first, "version", JSON::makeInt(this->m->json_version), 1); |
| 1759 | JSON j_params = JSON::makeDictionary(); | 1759 | JSON j_params = JSON::makeDictionary(); |
| 1760 | std::string decode_level_str; | 1760 | std::string decode_level_str; |
| 1761 | switch (m->decode_level) { | 1761 | switch (m->decode_level) { |
| @@ -1774,7 +1774,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | @@ -1774,7 +1774,7 @@ QPDFJob::doJSON(QPDF& pdf, Pipeline* p) | ||
| 1774 | } | 1774 | } |
| 1775 | j_params.addDictionaryMember( | 1775 | j_params.addDictionaryMember( |
| 1776 | "decodelevel", JSON::makeString(decode_level_str)); | 1776 | "decodelevel", JSON::makeString(decode_level_str)); |
| 1777 | - JSON::writeDictionaryItem(p, first, "parameters", j_params, 0); | 1777 | + JSON::writeDictionaryItem(p, first, "parameters", j_params, 1); |
| 1778 | 1778 | ||
| 1779 | bool all_keys = m->json_keys.empty(); | 1779 | bool all_keys = m->json_keys.empty(); |
| 1780 | // The list of selectable top-level keys id duplicated in the | 1780 | // The list of selectable top-level keys id duplicated in the |
libqpdf/QPDF_json.cc
| @@ -739,7 +739,7 @@ QPDF::writeJSONStream( | @@ -739,7 +739,7 @@ QPDF::writeJSONStream( | ||
| 739 | obj.getStreamJSON( | 739 | obj.getStreamJSON( |
| 740 | version, json_stream_data, decode_level, stream_p, filename)); | 740 | version, json_stream_data, decode_level, stream_p, filename)); |
| 741 | 741 | ||
| 742 | - JSON::writeDictionaryItem(p, first, key, j, 2); | 742 | + JSON::writeDictionaryItem(p, first, key, j, 3); |
| 743 | if (f) { | 743 | if (f) { |
| 744 | f_pl->finish(); | 744 | f_pl->finish(); |
| 745 | f_pl = nullptr; | 745 | f_pl = nullptr; |
| @@ -757,7 +757,7 @@ QPDF::writeJSONObject( | @@ -757,7 +757,7 @@ QPDF::writeJSONObject( | ||
| 757 | { | 757 | { |
| 758 | auto j = JSON::makeDictionary(); | 758 | auto j = JSON::makeDictionary(); |
| 759 | j.addDictionaryMember("value", obj.getJSON(version, true)); | 759 | j.addDictionaryMember("value", obj.getJSON(version, true)); |
| 760 | - JSON::writeDictionaryItem(p, first, key, j, 2); | 760 | + JSON::writeDictionaryItem(p, first, key, j, 3); |
| 761 | } | 761 | } |
| 762 | 762 | ||
| 763 | void | 763 | void |
| @@ -774,19 +774,23 @@ QPDF::writeJSON( | @@ -774,19 +774,23 @@ QPDF::writeJSON( | ||
| 774 | "QPDF::writeJSON: only version 2 is supported"); | 774 | "QPDF::writeJSON: only version 2 is supported"); |
| 775 | } | 775 | } |
| 776 | bool first = true; | 776 | bool first = true; |
| 777 | - JSON::writeDictionaryOpen(p, first, 0); | ||
| 778 | - JSON::writeDictionaryKey(p, first, "qpdf-v2", 0); | 777 | + if (complete) { |
| 778 | + JSON::writeDictionaryOpen(p, first, 0); | ||
| 779 | + } else { | ||
| 780 | + first = first_key; | ||
| 781 | + } | ||
| 782 | + JSON::writeDictionaryKey(p, first, "qpdf-v2", 1); | ||
| 779 | bool first_qpdf = true; | 783 | bool first_qpdf = true; |
| 780 | - JSON::writeDictionaryOpen(p, first_qpdf, 1); | 784 | + JSON::writeDictionaryOpen(p, first_qpdf, 2); |
| 781 | JSON::writeDictionaryItem( | 785 | JSON::writeDictionaryItem( |
| 782 | - p, first_qpdf, "pdfversion", JSON::makeString(getPDFVersion()), 1); | 786 | + p, first_qpdf, "pdfversion", JSON::makeString(getPDFVersion()), 2); |
| 783 | JSON::writeDictionaryItem( | 787 | JSON::writeDictionaryItem( |
| 784 | p, | 788 | p, |
| 785 | first_qpdf, | 789 | first_qpdf, |
| 786 | "maxobjectid", | 790 | "maxobjectid", |
| 787 | JSON::makeInt(QIntC::to_longlong(getObjectCount())), | 791 | JSON::makeInt(QIntC::to_longlong(getObjectCount())), |
| 788 | - 1); | ||
| 789 | - JSON::writeDictionaryKey(p, first_qpdf, "objects", 1); | 792 | + 2); |
| 793 | + JSON::writeDictionaryKey(p, first_qpdf, "objects", 2); | ||
| 790 | bool first_object = true; | 794 | bool first_object = true; |
| 791 | JSON::writeDictionaryOpen(p, first_object, 2); | 795 | JSON::writeDictionaryOpen(p, first_object, 2); |
| 792 | bool all_objects = wanted_objects.empty(); | 796 | bool all_objects = wanted_objects.empty(); |