Commit b15d0bf6e1305982450879b498a116d3387b705b
1 parent
920e9298
Add new method QPDF_Stream::writeStreamJSON
(Replacing the temporary implementation from the last commit.)
Showing
2 changed files
with
70 additions
and
51 deletions
libqpdf/QPDF_Stream.cc
| @@ -178,9 +178,9 @@ QPDF_Stream::unparse() | @@ -178,9 +178,9 @@ QPDF_Stream::unparse() | ||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | void | 180 | void |
| 181 | -QPDF_Stream::writeJSON(int json_version, JSON::Writer& p) | 181 | +QPDF_Stream::writeJSON(int json_version, JSON::Writer& jw) |
| 182 | { | 182 | { |
| 183 | - stream_dict.writeJSON(json_version, p); | 183 | + stream_dict.writeJSON(json_version, jw); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | JSON | 186 | JSON |
| @@ -233,58 +233,65 @@ QPDF_Stream::writeStreamJSON( | @@ -233,58 +233,65 @@ QPDF_Stream::writeStreamJSON( | ||
| 233 | break; | 233 | break; |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | - auto dict = this->stream_dict; | ||
| 237 | - JSON result = JSON::makeDictionary(); | ||
| 238 | - if (json_data != qpdf_sj_none) { | ||
| 239 | - Pl_Discard discard; | ||
| 240 | - Pl_Buffer buf_pl{"stream data"}; | ||
| 241 | - // buf_pl contains valid data and is ready for retrieval of the data. | ||
| 242 | - bool buf_pl_ready = false; | ||
| 243 | - bool filtered = false; | ||
| 244 | - bool filter = (decode_level != qpdf_dl_none); | ||
| 245 | - for (int attempt = 1; attempt <= 2; ++attempt) { | ||
| 246 | - Pipeline* data_pipeline = &discard; | ||
| 247 | - if (json_data == qpdf_sj_file) { | ||
| 248 | - // We need to capture the data to write | ||
| 249 | - data_pipeline = &buf_pl; | ||
| 250 | - } | ||
| 251 | - bool succeeded = | ||
| 252 | - pipeStreamData(data_pipeline, &filtered, 0, decode_level, false, (attempt == 1)); | ||
| 253 | - if (!succeeded || (filter && !filtered)) { | ||
| 254 | - // Try again | ||
| 255 | - filter = false; | ||
| 256 | - decode_level = qpdf_dl_none; | ||
| 257 | - buf_pl.getString(); // reset buf_pl | ||
| 258 | - } else { | ||
| 259 | - buf_pl_ready = true; | ||
| 260 | - break; | ||
| 261 | - } | ||
| 262 | - } | ||
| 263 | - if (!buf_pl_ready) { | ||
| 264 | - throw std::logic_error("QPDF_Stream: failed to get stream data"); | ||
| 265 | - } | ||
| 266 | - // We can use unsafeShallowCopy because we are only touching top-level keys. | ||
| 267 | - dict = this->stream_dict.unsafeShallowCopy(); | ||
| 268 | - dict.removeKey("/Length"); | ||
| 269 | - if (filter && filtered) { | ||
| 270 | - dict.removeKey("/Filter"); | ||
| 271 | - dict.removeKey("/DecodeParms"); | ||
| 272 | - } | ||
| 273 | - if (json_data == qpdf_sj_file) { | ||
| 274 | - result.addDictionaryMember("datafile", JSON::makeString(data_filename)); | ||
| 275 | - | ||
| 276 | - p->writeString(buf_pl.getString()); | ||
| 277 | - } else if (json_data == qpdf_sj_inline) { | ||
| 278 | - if (!no_data_key) { | ||
| 279 | - result.addDictionaryMember( | ||
| 280 | - "data", JSON::makeBlob(StreamBlobProvider(this, decode_level))); | ||
| 281 | - } | 236 | + jw.writeStart('{'); |
| 237 | + | ||
| 238 | + if (json_data == qpdf_sj_none) { | ||
| 239 | + jw.writeNext(); | ||
| 240 | + jw << R"("dict": )"; | ||
| 241 | + stream_dict.writeJSON(json_version, jw); | ||
| 242 | + jw.writeEnd('}'); | ||
| 243 | + return decode_level; | ||
| 244 | + } | ||
| 245 | + | ||
| 246 | + Pl_Discard discard; | ||
| 247 | + Pl_Buffer buf_pl{"stream data"}; | ||
| 248 | + Pipeline* data_pipeline = &buf_pl; | ||
| 249 | + if (no_data_key && json_data == qpdf_sj_inline) { | ||
| 250 | + data_pipeline = &discard; | ||
| 251 | + } | ||
| 252 | + // pipeStreamData produced valid data. | ||
| 253 | + bool buf_pl_ready = false; | ||
| 254 | + bool filtered = false; | ||
| 255 | + bool filter = (decode_level != qpdf_dl_none); | ||
| 256 | + for (int attempt = 1; attempt <= 2; ++attempt) { | ||
| 257 | + bool succeeded = | ||
| 258 | + pipeStreamData(data_pipeline, &filtered, 0, decode_level, false, (attempt == 1)); | ||
| 259 | + if (!succeeded || (filter && !filtered)) { | ||
| 260 | + // Try again | ||
| 261 | + filter = false; | ||
| 262 | + decode_level = qpdf_dl_none; | ||
| 263 | + buf_pl.getString(); // reset buf_pl | ||
| 282 | } else { | 264 | } else { |
| 283 | - throw std::logic_error("QPDF_Stream: unexpected value of json_data"); | 265 | + buf_pl_ready = true; |
| 266 | + break; | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | + if (!buf_pl_ready) { | ||
| 270 | + throw std::logic_error("QPDF_Stream: failed to get stream data"); | ||
| 271 | + } | ||
| 272 | + // We can use unsafeShallowCopy because we are only touching top-level keys. | ||
| 273 | + auto dict = stream_dict.unsafeShallowCopy(); | ||
| 274 | + dict.removeKey("/Length"); | ||
| 275 | + if (filter && filtered) { | ||
| 276 | + dict.removeKey("/Filter"); | ||
| 277 | + dict.removeKey("/DecodeParms"); | ||
| 278 | + } | ||
| 279 | + if (json_data == qpdf_sj_file) { | ||
| 280 | + jw.writeNext() << R"("datafile": ")" << JSON::Writer::encode_string(data_filename) << "\""; | ||
| 281 | + p->writeString(buf_pl.getString()); | ||
| 282 | + } else if (json_data == qpdf_sj_inline) { | ||
| 283 | + if (!no_data_key) { | ||
| 284 | + jw.writeNext() << R"("data": ")"; | ||
| 285 | + jw.writeBase64(buf_pl.getString()) << "\""; | ||
| 284 | } | 286 | } |
| 287 | + } else { | ||
| 288 | + throw std::logic_error("QPDF_Stream::writeStreamJSON : unexpected value of json_data"); | ||
| 285 | } | 289 | } |
| 286 | - result.addDictionaryMember("dict", dict.getJSON(json_version)); | ||
| 287 | - jw << std::move(result); | 290 | + |
| 291 | + jw.writeNext() << R"("dict": )"; | ||
| 292 | + dict.writeJSON(json_version, jw); | ||
| 293 | + jw.writeEnd('}'); | ||
| 294 | + | ||
| 288 | return decode_level; | 295 | return decode_level; |
| 289 | } | 296 | } |
| 290 | 297 |
libqpdf/qpdf/JSON_writer.hh
| @@ -3,6 +3,8 @@ | @@ -3,6 +3,8 @@ | ||
| 3 | 3 | ||
| 4 | #include <qpdf/JSON.hh> | 4 | #include <qpdf/JSON.hh> |
| 5 | #include <qpdf/Pipeline.hh> | 5 | #include <qpdf/Pipeline.hh> |
| 6 | +#include <qpdf/Pl_Base64.hh> | ||
| 7 | +#include <qpdf/Pl_Concatenate.hh> | ||
| 6 | 8 | ||
| 7 | #include <string_view> | 9 | #include <string_view> |
| 8 | 10 | ||
| @@ -28,6 +30,16 @@ class JSON::Writer | @@ -28,6 +30,16 @@ class JSON::Writer | ||
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | Writer& | 32 | Writer& |
| 33 | + writeBase64(std::string_view sv) | ||
| 34 | + { | ||
| 35 | + Pl_Concatenate cat{"writer concat", p}; | ||
| 36 | + Pl_Base64 base{"writer base64", &cat, Pl_Base64::a_encode}; | ||
| 37 | + base.write(reinterpret_cast<unsigned char const*>(sv.data()), sv.size()); | ||
| 38 | + base.finish(); | ||
| 39 | + return *this; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + Writer& | ||
| 31 | writeNext() | 43 | writeNext() |
| 32 | { | 44 | { |
| 33 | auto n = indent; | 45 | auto n = indent; |