Commit b15d0bf6e1305982450879b498a116d3387b705b

Authored by m-holger
1 parent 920e9298

Add new method QPDF_Stream::writeStreamJSON

(Replacing the temporary implementation from the last commit.)
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;