aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2022-05-04 22:28:12 +0200
committerJay Berkenbilt <ejb@ql.org>2022-05-07 01:14:52 +0200
commit0500d4347a6d31ef05fd860559e380c2e488c194 (patch)
tree26a22f65b7400d7fd26df5720fe2bbabd7b6de09
parent05fda4afa289ef248804865d7648c9ac3ae75fbd (diff)
downloadqpdf-0500d4347a6d31ef05fd860559e380c2e488c194.tar.zst
JSON: add blob type that generates base64-encoded binary data
-rw-r--r--ChangeLog4
-rw-r--r--TODO5
-rw-r--r--cSpell.json1
-rw-r--r--include/qpdf/JSON.hh14
-rw-r--r--libqpdf/JSON.cc24
-rw-r--r--libtests/json.cc14
6 files changed, 57 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 53e1e8d6..8cf93186 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/TODO b/TODO
index b53d175f..11204e6f 100644
--- a/TODO
+++ b/TODO
@@ -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
diff --git a/cSpell.json b/cSpell.json
index cba39d9a..1cc0363e 100644
--- a/cSpell.json
+++ b/cSpell.json
@@ -199,6 +199,7 @@
"itemizedlist",
"jarr",
"jbig",
+ "jblob",
"jdimension",
"jdouble",
"jerr",
diff --git a/include/qpdf/JSON.hh b/include/qpdf/JSON.hh
index 435c2362..4f4162fc 100644
--- a/include/qpdf/JSON.hh
+++ b/include/qpdf/JSON.hh
@@ -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>);
diff --git a/libqpdf/JSON.cc b/libqpdf/JSON.cc
index 71ea33d7..8549b7ed 100644
--- a/libqpdf/JSON.cc
+++ b/libqpdf/JSON.cc
@@ -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
{
diff --git a/libtests/json.cc b/libtests/json.cc
index 3844222f..b386e6eb 100644
--- a/libtests/json.cc
+++ b/libtests/json.cc
@@ -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