Add new writeJSON methods

Create an alternative to getJSON to allow an object handle to be written as JSON without the overhead of creating a JSON object.
This commit is contained in:
m-holger 2024-02-09 13:09:08 +00:00
parent 9e90007a4a
commit e2737ab646
33 changed files with 235 additions and 3 deletions

View File

@ -1353,6 +1353,8 @@ class QPDFObjectHandle
return obj.get();
}
void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false);
private:
QPDF_Array* asArray();
QPDF_Bool* asBool();

View File

@ -3,6 +3,7 @@
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_QPDFTokenizer.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFExc.hh>
#include <qpdf/QPDFLogger.hh>
@ -1621,6 +1622,18 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
}
}
void
QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect)
{
if (!dereference_indirect && isIndirect()) {
p << "\"" << getObjGen().unparse(' ') << " R\"";
} else if (!dereference()) {
throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
} else {
obj->writeJSON(json_version, p);
}
}
JSON
QPDFObjectHandle::getStreamJSON(
int json_version,

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Array.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFObject_private.hh>
#include <qpdf/QTC.hh>
@ -180,6 +181,43 @@ QPDF_Array::getJSON(int json_version)
return j_array;
}
void
QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
{
p.writeStart('[');
if (sp) {
int next = 0;
for (auto& item: sp->elements) {
int key = item.first;
for (int j = next; j < key; ++j) {
p.writeNext() << "null";
}
p.writeNext();
auto og = item.second->getObjGen();
if (og.isIndirect()) {
p << "\"" << og.unparse(' ') << " R\"";
} else {
item.second->writeJSON(json_version, p);
}
next = ++key;
}
for (int j = next; j < sp->size; ++j) {
p.writeNext() << "null";
}
} else {
for (auto const& item: elements) {
p.writeNext();
auto og = item->getObjGen();
if (og.isIndirect()) {
p << "\"" << og.unparse(' ') << " R\"";
} else {
item->writeJSON(json_version, p);
}
}
}
p.writeEnd(']');
}
QPDFObjectHandle
QPDF_Array::at(int n) const noexcept
{

View File

@ -1,5 +1,7 @@
#include <qpdf/QPDF_Bool.hh>
#include <qpdf/JSON_writer.hh>
QPDF_Bool::QPDF_Bool(bool val) :
QPDFValue(::ot_boolean, "boolean"),
val(val)
@ -30,6 +32,12 @@ QPDF_Bool::getJSON(int json_version)
return JSON::makeBool(this->val);
}
void
QPDF_Bool::writeJSON(int json_version, JSON::Writer& p)
{
p << val;
}
bool
QPDF_Bool::getVal() const
{

View File

@ -34,3 +34,9 @@ QPDF_Destroyed::getJSON(int json_version)
throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF");
return JSON::makeNull();
}
void
QPDF_Destroyed::writeJSON(int json_version, JSON::Writer& p)
{
throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF");
}

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QPDFObject_private.hh>
#include <qpdf/QPDF_Name.hh>
#include <qpdf/QPDF_Null.hh>
@ -91,6 +92,33 @@ QPDF_Dictionary::getJSON(int json_version)
return j;
}
void
QPDF_Dictionary::writeJSON(int json_version, JSON::Writer& p)
{
p.writeStart('{');
for (auto& iter: this->items) {
if (!iter.second.isNull()) {
p.writeNext();
if (json_version == 1) {
p << "\"" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first)) << "\": ";
} else {
bool has_8bit_chars;
bool is_valid_utf8;
bool is_utf16;
QUtil::analyze_encoding(iter.first, has_8bit_chars, is_valid_utf8, is_utf16);
if (!has_8bit_chars || is_valid_utf8) {
p << "\"" << JSON::Writer::encode_string(iter.first) << "\": ";
} else {
p << "\"n:" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first))
<< "\": ";
}
}
iter.second.writeJSON(json_version, p);
}
}
p.writeEnd('}');
}
bool
QPDF_Dictionary::hasKey(std::string const& key)
{

View File

@ -1,5 +1,7 @@
#include <qpdf/QPDF_InlineImage.hh>
#include <qpdf/JSON_writer.hh>
QPDF_InlineImage::QPDF_InlineImage(std::string const& val) :
QPDFValue(::ot_inlineimage, "inline-image"),
val(val)
@ -29,3 +31,9 @@ QPDF_InlineImage::getJSON(int json_version)
{
return JSON::makeNull();
}
void
QPDF_InlineImage::writeJSON(int json_version, JSON::Writer& p)
{
p << "null";
}

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Integer.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QUtil.hh>
QPDF_Integer::QPDF_Integer(long long val) :
@ -32,6 +33,12 @@ QPDF_Integer::getJSON(int json_version)
return JSON::makeInt(this->val);
}
void
QPDF_Integer::writeJSON(int json_version, JSON::Writer& p)
{
p << std::to_string(this->val);
}
long long
QPDF_Integer::getVal() const
{

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Name.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QUtil.hh>
QPDF_Name::QPDF_Name(std::string const& name) :
@ -68,3 +69,21 @@ QPDF_Name::getJSON(int json_version)
}
}
}
void
QPDF_Name::writeJSON(int json_version, JSON::Writer& p)
{
if (json_version == 1) {
p << "\"" << JSON::Writer::encode_string(normalizeName(name)) << "\"";
} else {
bool has_8bit_chars;
bool is_valid_utf8;
bool is_utf16;
QUtil::analyze_encoding(this->name, has_8bit_chars, is_valid_utf8, is_utf16);
if (!has_8bit_chars || is_valid_utf8) {
p << "\"" << JSON::Writer::encode_string(name) << "\"";
} else {
p << "\"n:" << JSON::Writer::encode_string(normalizeName(name)) << "\"";
}
}
}

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Null.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QPDFObject_private.hh>
QPDF_Null::QPDF_Null() :
@ -49,3 +50,9 @@ QPDF_Null::getJSON(int json_version)
// If this is updated, QPDF_Array::getJSON must also be updated.
return JSON::makeNull();
}
void
QPDF_Null::writeJSON(int json_version, JSON::Writer& p)
{
p << "null";
}

View File

@ -1,5 +1,7 @@
#include <qpdf/QPDF_Operator.hh>
#include <qpdf/JSON_writer.hh>
QPDF_Operator::QPDF_Operator(std::string const& val) :
QPDFValue(::ot_operator, "operator"),
val(val)
@ -29,3 +31,9 @@ QPDF_Operator::getJSON(int json_version)
{
return JSON::makeNull();
}
void
QPDF_Operator::writeJSON(int json_version, JSON::Writer& p)
{
p << "null";
}

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_Real.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QUtil.hh>
QPDF_Real::QPDF_Real(std::string const& val) :
@ -56,3 +57,18 @@ QPDF_Real::getJSON(int json_version)
}
return JSON::makeNumber(result);
}
void
QPDF_Real::writeJSON(int json_version, JSON::Writer& p)
{
if (this->val.length() == 0) {
// Can't really happen...
p << "0";
} else if (this->val.at(0) == '.') {
p << "0" << this->val;
} else if (this->val.length() >= 2 && this->val.at(0) == '-' && this->val.at(1) == '.') {
p << "-0." << this->val.substr(2);
} else {
p << this->val;
}
}

View File

@ -32,3 +32,9 @@ QPDF_Reserved::getJSON(int json_version)
throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object");
return JSON::makeNull();
}
void
QPDF_Reserved::writeJSON(int json_version, JSON::Writer& p)
{
throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object");
}

View File

@ -1,6 +1,7 @@
#include <qpdf/QPDF_Stream.hh>
#include <qpdf/ContentNormalizer.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/Pipeline.hh>
#include <qpdf/Pl_Base64.hh>
#include <qpdf/Pl_Buffer.hh>
@ -185,6 +186,12 @@ QPDF_Stream::getJSON(int json_version)
return getStreamJSON(json_version, qpdf_sj_none, qpdf_dl_none, nullptr, "");
}
void
QPDF_Stream::writeJSON(int json_version, JSON::Writer& p)
{
stream_dict.writeJSON(json_version, p);
}
JSON
QPDF_Stream::getStreamJSON(
int json_version,

View File

@ -1,5 +1,6 @@
#include <qpdf/QPDF_String.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/QUtil.hh>
// DO NOT USE ctype -- it is locale dependent for some things, and it's not worth the risk of
@ -74,6 +75,30 @@ QPDF_String::getJSON(int json_version)
return JSON::makeString(result);
}
void
QPDF_String::writeJSON(int json_version, JSON::Writer& p)
{
auto candidate = getUTF8Val();
if (json_version == 1) {
p << "\"" << JSON::Writer::encode_string(candidate) << "\"";
} else {
// See if we can unambiguously represent as Unicode.
if (QUtil::is_utf16(this->val) || QUtil::is_explicit_utf8(this->val)) {
p << "\"u:" << JSON::Writer::encode_string(candidate) <<"\"";
return;
} else if (!useHexString()) {
std::string test;
if (QUtil::utf8_to_pdf_doc(candidate, test, '?') && (test == this->val)) {
// This is a PDF-doc string that can be losslessly encoded as Unicode.
p << "\"u:" << JSON::Writer::encode_string(candidate) <<"\"";
return;
}
}
p << "\"b:" << QUtil::hex_encode(val) <<"\"";
}
}
bool
QPDF_String::useHexString() const
{

View File

@ -33,3 +33,9 @@ QPDF_Unresolved::getJSON(int json_version)
throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle");
return JSON::makeNull();
}
void
QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p)
{
throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle");
}

View File

@ -1,6 +1,7 @@
#include <qpdf/QPDF.hh>
#include <qpdf/FileInputSource.hh>
#include <qpdf/JSON_writer.hh>
#include <qpdf/Pl_Base64.hh>
#include <qpdf/Pl_StdioFile.hh>
#include <qpdf/QIntC.hh>
@ -864,9 +865,15 @@ void
QPDF::writeJSONObject(
int version, Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle& obj)
{
auto j = JSON::makeDictionary();
j.addDictionaryMember("value", obj.getJSON(version, true));
JSON::writeDictionaryItem(p, first, key, j, 3);
if (first) {
*p << "\n \"" << key << "\": {\n \"value\": ";
first = false;
} else {
*p << ",\n \"" << key << "\": {\n \"value\": ";
}
auto w = JSON::Writer(p, 4);
obj.writeJSON(version, w, true);
*p << "\n }";
}
void

View File

@ -38,6 +38,11 @@ class QPDFObject
{
return value->getJSON(json_version);
}
void
writeJSON(int json_version, JSON::Writer& p)
{
return value->writeJSON(json_version, p);
}
std::string
getStringValue() const
{

View File

@ -25,6 +25,7 @@ class QPDFValue: public std::enable_shared_from_this<QPDFValue>
virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0;
virtual std::string unparse() = 0;
virtual JSON getJSON(int json_version) = 0;
virtual void writeJSON(int json_version, JSON::Writer& p) = 0;
struct JSON_Descr
{

View File

@ -23,6 +23,7 @@ class QPDF_Array: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
void disconnect() override;
int

View File

@ -11,6 +11,8 @@ class QPDF_Bool: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
bool getVal() const;
private:

View File

@ -10,6 +10,7 @@ class QPDF_Destroyed: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
static std::shared_ptr<QPDFValue> getInstance();
private:

View File

@ -17,6 +17,7 @@ class QPDF_Dictionary: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
void disconnect() override;
// hasKey() and getKeys() treat keys with null values as if they aren't there. getKey() returns

View File

@ -11,6 +11,7 @@ class QPDF_InlineImage: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
std::string
getStringValue() const override
{

View File

@ -11,6 +11,7 @@ class QPDF_Integer: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
long long getVal() const;
private:

View File

@ -11,6 +11,7 @@ class QPDF_Name: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
// Put # into strings with characters unsuitable for name token
static std::string normalizeName(std::string const& name);

View File

@ -19,6 +19,7 @@ class QPDF_Null: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
private:
QPDF_Null();

View File

@ -11,6 +11,7 @@ class QPDF_Operator: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
std::string
getStringValue() const override
{

View File

@ -13,6 +13,7 @@ class QPDF_Real: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
std::string
getStringValue() const override
{

View File

@ -11,6 +11,7 @@ class QPDF_Reserved: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
private:
QPDF_Reserved();

View File

@ -26,6 +26,7 @@ class QPDF_Stream: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
void setDescription(
QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) override;
void disconnect() override;

View File

@ -17,6 +17,7 @@ class QPDF_String: public QPDFValue
std::string unparse() override;
std::string unparse(bool force_binary);
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
std::string getUTF8Val() const;
std::string
getStringValue() const override

View File

@ -11,6 +11,7 @@ class QPDF_Unresolved: public QPDFValue
std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
std::string unparse() override;
JSON getJSON(int json_version) override;
void writeJSON(int json_version, JSON::Writer& p) override;
private:
QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og);