JSON: add blob type that generates base64-encoded binary data

This commit is contained in:
Jay Berkenbilt 2022-05-04 16:28:12 -04:00
parent 05fda4afa2
commit 0500d4347a
6 changed files with 57 additions and 5 deletions

View File

@ -1,5 +1,9 @@
2022-05-04 Jay Berkenbilt <ejb@ql.org>
* JSON: add a new "blob" type that takes a function to write data
into. The blob is serialized as a base64-encoded representation of
whatever is written to the function.
* FileInputSource has new constructors that eliminate the need to
call setFilename or setFile in most cases.

5
TODO
View File

@ -51,11 +51,6 @@ library, when context is available, to have a pipeline rather than a
FILE* or std::ostream. This makes it possible for people to capture
output more flexibly.
Have a json blob defined by a function that takes a pipeline and
writes data to the pipeline. It's writer should create a Pl_Base64 ->
Pl_Concatenate in front of the pipeline passed to write and call the
function with that.
For json output, do not unparse to string. Use the writers instead.
Write incrementally. This changes ordering only, but we should be able
manually update the test output for those cases. Objects should be

View File

@ -199,6 +199,7 @@
"itemizedlist",
"jarr",
"jbig",
"jblob",
"jdimension",
"jdouble",
"jerr",

View File

@ -122,6 +122,13 @@ class JSON
QPDF_DLL
static JSON makeNull();
// A blob serializes as a string. The function will be called by
// JSON with a pipeline and should write binary data to the
// pipeline but not call finish(). JSON will call finish() at the
// right time.
QPDF_DLL
static JSON makeBlob(std::function<void(Pipeline*)>);
QPDF_DLL
bool isArray() const;
@ -323,6 +330,13 @@ class JSON
virtual ~JSON_null() = default;
virtual void write(Pipeline*, size_t depth) const;
};
struct JSON_blob: public JSON_value
{
JSON_blob(std::function<void(Pipeline*)> fn);
virtual ~JSON_blob() = default;
virtual void write(Pipeline*, size_t depth) const;
std::function<void(Pipeline*)> fn;
};
JSON(std::shared_ptr<JSON_value>);

View File

@ -1,6 +1,8 @@
#include <qpdf/JSON.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Base64.hh>
#include <qpdf/Pl_Concatenate.hh>
#include <qpdf/Pl_String.hh>
#include <qpdf/QTC.hh>
#include <qpdf/QUtil.hh>
@ -168,6 +170,22 @@ JSON::JSON_null::write(Pipeline* p, size_t) const
*p << "null";
}
JSON::JSON_blob::JSON_blob(std::function<void(Pipeline*)> fn) :
fn(fn)
{
}
void
JSON::JSON_blob::write(Pipeline* p, size_t) const
{
*p << "\"";
Pl_Concatenate cat("blob concatenate", p);
Pl_Base64 base64("blob base64", &cat, Pl_Base64::a_encode);
fn(&base64);
base64.finish();
*p << "\"";
}
void
JSON::write(Pipeline* p, size_t depth) const
{
@ -306,6 +324,12 @@ JSON::makeNull()
return JSON(std::make_shared<JSON_null>());
}
JSON
JSON::makeBlob(std::function<void(Pipeline*)> fn)
{
return JSON(std::make_shared<JSON_blob>(fn));
}
bool
JSON::isArray() const
{

View File

@ -1,6 +1,7 @@
#include <qpdf/assert_test.h>
#include <qpdf/JSON.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <iostream>
@ -113,6 +114,19 @@ test_main()
{"c", "[\n true\n]"},
};
assert(dvalue == xdvalue);
auto blob_data = [](Pipeline* p) {
*p << "\x01\x02\x03\x04\x05\xff\xfe\xfd\xfc\xfb";
};
JSON jblob = JSON::makeDictionary();
jblob.addDictionaryMember("normal", JSON::parse(R"("string")"));
jblob.addDictionaryMember("blob", JSON::makeBlob(blob_data));
// cSpell:ignore AQIDBAX
check(
jblob,
"{\n"
" \"blob\": \"AQIDBAX//v38+w==\",\n"
" \"normal\": \"string\"\n"
"}");
}
static void