Commit 0500d4347a6d31ef05fd860559e380c2e488c194
1 parent
05fda4af
JSON: add blob type that generates base64-encoded binary data
Showing
6 changed files
with
57 additions
and
5 deletions
ChangeLog
| 1 | 1 | 2022-05-04 Jay Berkenbilt <ejb@ql.org> |
| 2 | 2 | |
| 3 | + * JSON: add a new "blob" type that takes a function to write data | |
| 4 | + into. The blob is serialized as a base64-encoded representation of | |
| 5 | + whatever is written to the function. | |
| 6 | + | |
| 3 | 7 | * FileInputSource has new constructors that eliminate the need to |
| 4 | 8 | call setFilename or setFile in most cases. |
| 5 | 9 | ... | ... |
TODO
| ... | ... | @@ -51,11 +51,6 @@ library, when context is available, to have a pipeline rather than a |
| 51 | 51 | FILE* or std::ostream. This makes it possible for people to capture |
| 52 | 52 | output more flexibly. |
| 53 | 53 | |
| 54 | -Have a json blob defined by a function that takes a pipeline and | |
| 55 | -writes data to the pipeline. It's writer should create a Pl_Base64 -> | |
| 56 | -Pl_Concatenate in front of the pipeline passed to write and call the | |
| 57 | -function with that. | |
| 58 | - | |
| 59 | 54 | For json output, do not unparse to string. Use the writers instead. |
| 60 | 55 | Write incrementally. This changes ordering only, but we should be able |
| 61 | 56 | manually update the test output for those cases. Objects should be | ... | ... |
cSpell.json
include/qpdf/JSON.hh
| ... | ... | @@ -122,6 +122,13 @@ class JSON |
| 122 | 122 | QPDF_DLL |
| 123 | 123 | static JSON makeNull(); |
| 124 | 124 | |
| 125 | + // A blob serializes as a string. The function will be called by | |
| 126 | + // JSON with a pipeline and should write binary data to the | |
| 127 | + // pipeline but not call finish(). JSON will call finish() at the | |
| 128 | + // right time. | |
| 129 | + QPDF_DLL | |
| 130 | + static JSON makeBlob(std::function<void(Pipeline*)>); | |
| 131 | + | |
| 125 | 132 | QPDF_DLL |
| 126 | 133 | bool isArray() const; |
| 127 | 134 | |
| ... | ... | @@ -323,6 +330,13 @@ class JSON |
| 323 | 330 | virtual ~JSON_null() = default; |
| 324 | 331 | virtual void write(Pipeline*, size_t depth) const; |
| 325 | 332 | }; |
| 333 | + struct JSON_blob: public JSON_value | |
| 334 | + { | |
| 335 | + JSON_blob(std::function<void(Pipeline*)> fn); | |
| 336 | + virtual ~JSON_blob() = default; | |
| 337 | + virtual void write(Pipeline*, size_t depth) const; | |
| 338 | + std::function<void(Pipeline*)> fn; | |
| 339 | + }; | |
| 326 | 340 | |
| 327 | 341 | JSON(std::shared_ptr<JSON_value>); |
| 328 | 342 | ... | ... |
libqpdf/JSON.cc
| 1 | 1 | #include <qpdf/JSON.hh> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/BufferInputSource.hh> |
| 4 | +#include <qpdf/Pl_Base64.hh> | |
| 5 | +#include <qpdf/Pl_Concatenate.hh> | |
| 4 | 6 | #include <qpdf/Pl_String.hh> |
| 5 | 7 | #include <qpdf/QTC.hh> |
| 6 | 8 | #include <qpdf/QUtil.hh> |
| ... | ... | @@ -168,6 +170,22 @@ JSON::JSON_null::write(Pipeline* p, size_t) const |
| 168 | 170 | *p << "null"; |
| 169 | 171 | } |
| 170 | 172 | |
| 173 | +JSON::JSON_blob::JSON_blob(std::function<void(Pipeline*)> fn) : | |
| 174 | + fn(fn) | |
| 175 | +{ | |
| 176 | +} | |
| 177 | + | |
| 178 | +void | |
| 179 | +JSON::JSON_blob::write(Pipeline* p, size_t) const | |
| 180 | +{ | |
| 181 | + *p << "\""; | |
| 182 | + Pl_Concatenate cat("blob concatenate", p); | |
| 183 | + Pl_Base64 base64("blob base64", &cat, Pl_Base64::a_encode); | |
| 184 | + fn(&base64); | |
| 185 | + base64.finish(); | |
| 186 | + *p << "\""; | |
| 187 | +} | |
| 188 | + | |
| 171 | 189 | void |
| 172 | 190 | JSON::write(Pipeline* p, size_t depth) const |
| 173 | 191 | { |
| ... | ... | @@ -306,6 +324,12 @@ JSON::makeNull() |
| 306 | 324 | return JSON(std::make_shared<JSON_null>()); |
| 307 | 325 | } |
| 308 | 326 | |
| 327 | +JSON | |
| 328 | +JSON::makeBlob(std::function<void(Pipeline*)> fn) | |
| 329 | +{ | |
| 330 | + return JSON(std::make_shared<JSON_blob>(fn)); | |
| 331 | +} | |
| 332 | + | |
| 309 | 333 | bool |
| 310 | 334 | JSON::isArray() const |
| 311 | 335 | { | ... | ... |
libtests/json.cc
| 1 | 1 | #include <qpdf/assert_test.h> |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/JSON.hh> |
| 4 | +#include <qpdf/Pipeline.hh> | |
| 4 | 5 | #include <qpdf/QPDFObjectHandle.hh> |
| 5 | 6 | #include <iostream> |
| 6 | 7 | |
| ... | ... | @@ -113,6 +114,19 @@ test_main() |
| 113 | 114 | {"c", "[\n true\n]"}, |
| 114 | 115 | }; |
| 115 | 116 | assert(dvalue == xdvalue); |
| 117 | + auto blob_data = [](Pipeline* p) { | |
| 118 | + *p << "\x01\x02\x03\x04\x05\xff\xfe\xfd\xfc\xfb"; | |
| 119 | + }; | |
| 120 | + JSON jblob = JSON::makeDictionary(); | |
| 121 | + jblob.addDictionaryMember("normal", JSON::parse(R"("string")")); | |
| 122 | + jblob.addDictionaryMember("blob", JSON::makeBlob(blob_data)); | |
| 123 | + // cSpell:ignore AQIDBAX | |
| 124 | + check( | |
| 125 | + jblob, | |
| 126 | + "{\n" | |
| 127 | + " \"blob\": \"AQIDBAX//v38+w==\",\n" | |
| 128 | + " \"normal\": \"string\"\n" | |
| 129 | + "}"); | |
| 116 | 130 | } |
| 117 | 131 | |
| 118 | 132 | static void | ... | ... |