Commit e2737ab646bff6aa07ba72e0cc15cc955d9afcc0

Authored by m-holger
1 parent 9e90007a

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.
include/qpdf/QPDFObjectHandle.hh
... ... @@ -1353,6 +1353,8 @@ class QPDFObjectHandle
1353 1353 return obj.get();
1354 1354 }
1355 1355  
  1356 + void writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect = false);
  1357 +
1356 1358 private:
1357 1359 QPDF_Array* asArray();
1358 1360 QPDF_Bool* asBool();
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -3,6 +3,7 @@
3 3 #include <qpdf/BufferInputSource.hh>
4 4 #include <qpdf/Pl_Buffer.hh>
5 5 #include <qpdf/Pl_QPDFTokenizer.hh>
  6 +#include <qpdf/JSON_writer.hh>
6 7 #include <qpdf/QPDF.hh>
7 8 #include <qpdf/QPDFExc.hh>
8 9 #include <qpdf/QPDFLogger.hh>
... ... @@ -1621,6 +1622,18 @@ QPDFObjectHandle::getJSON(int json_version, bool dereference_indirect)
1621 1622 }
1622 1623 }
1623 1624  
  1625 +void
  1626 +QPDFObjectHandle::writeJSON(int json_version, JSON::Writer& p, bool dereference_indirect)
  1627 +{
  1628 + if (!dereference_indirect && isIndirect()) {
  1629 + p << "\"" << getObjGen().unparse(' ') << " R\"";
  1630 + } else if (!dereference()) {
  1631 + throw std::logic_error("attempted to dereference an uninitialized QPDFObjectHandle");
  1632 + } else {
  1633 + obj->writeJSON(json_version, p);
  1634 + }
  1635 +}
  1636 +
1624 1637 JSON
1625 1638 QPDFObjectHandle::getStreamJSON(
1626 1639 int json_version,
... ...
libqpdf/QPDF_Array.cc
1 1 #include <qpdf/QPDF_Array.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QPDFObjectHandle.hh>
4 5 #include <qpdf/QPDFObject_private.hh>
5 6 #include <qpdf/QTC.hh>
... ... @@ -180,6 +181,43 @@ QPDF_Array::getJSON(int json_version)
180 181 return j_array;
181 182 }
182 183  
  184 +void
  185 +QPDF_Array::writeJSON(int json_version, JSON::Writer& p)
  186 +{
  187 + p.writeStart('[');
  188 + if (sp) {
  189 + int next = 0;
  190 + for (auto& item: sp->elements) {
  191 + int key = item.first;
  192 + for (int j = next; j < key; ++j) {
  193 + p.writeNext() << "null";
  194 + }
  195 + p.writeNext();
  196 + auto og = item.second->getObjGen();
  197 + if (og.isIndirect()) {
  198 + p << "\"" << og.unparse(' ') << " R\"";
  199 + } else {
  200 + item.second->writeJSON(json_version, p);
  201 + }
  202 + next = ++key;
  203 + }
  204 + for (int j = next; j < sp->size; ++j) {
  205 + p.writeNext() << "null";
  206 + }
  207 + } else {
  208 + for (auto const& item: elements) {
  209 + p.writeNext();
  210 + auto og = item->getObjGen();
  211 + if (og.isIndirect()) {
  212 + p << "\"" << og.unparse(' ') << " R\"";
  213 + } else {
  214 + item->writeJSON(json_version, p);
  215 + }
  216 + }
  217 + }
  218 + p.writeEnd(']');
  219 +}
  220 +
183 221 QPDFObjectHandle
184 222 QPDF_Array::at(int n) const noexcept
185 223 {
... ...
libqpdf/QPDF_Bool.cc
1 1 #include <qpdf/QPDF_Bool.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
  4 +
3 5 QPDF_Bool::QPDF_Bool(bool val) :
4 6 QPDFValue(::ot_boolean, "boolean"),
5 7 val(val)
... ... @@ -30,6 +32,12 @@ QPDF_Bool::getJSON(int json_version)
30 32 return JSON::makeBool(this->val);
31 33 }
32 34  
  35 +void
  36 +QPDF_Bool::writeJSON(int json_version, JSON::Writer& p)
  37 +{
  38 + p << val;
  39 +}
  40 +
33 41 bool
34 42 QPDF_Bool::getVal() const
35 43 {
... ...
libqpdf/QPDF_Destroyed.cc
... ... @@ -34,3 +34,9 @@ QPDF_Destroyed::getJSON(int json_version)
34 34 throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF");
35 35 return JSON::makeNull();
36 36 }
  37 +
  38 +void
  39 +QPDF_Destroyed::writeJSON(int json_version, JSON::Writer& p)
  40 +{
  41 + throw std::logic_error("attempted to get JSON from a QPDFObjectHandle from a destroyed QPDF");
  42 +}
37 43 \ No newline at end of file
... ...
libqpdf/QPDF_Dictionary.cc
1 1 #include <qpdf/QPDF_Dictionary.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QPDFObject_private.hh>
4 5 #include <qpdf/QPDF_Name.hh>
5 6 #include <qpdf/QPDF_Null.hh>
... ... @@ -91,6 +92,33 @@ QPDF_Dictionary::getJSON(int json_version)
91 92 return j;
92 93 }
93 94  
  95 +void
  96 +QPDF_Dictionary::writeJSON(int json_version, JSON::Writer& p)
  97 +{
  98 + p.writeStart('{');
  99 + for (auto& iter: this->items) {
  100 + if (!iter.second.isNull()) {
  101 + p.writeNext();
  102 + if (json_version == 1) {
  103 + p << "\"" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first)) << "\": ";
  104 + } else {
  105 + bool has_8bit_chars;
  106 + bool is_valid_utf8;
  107 + bool is_utf16;
  108 + QUtil::analyze_encoding(iter.first, has_8bit_chars, is_valid_utf8, is_utf16);
  109 + if (!has_8bit_chars || is_valid_utf8) {
  110 + p << "\"" << JSON::Writer::encode_string(iter.first) << "\": ";
  111 + } else {
  112 + p << "\"n:" << JSON::Writer::encode_string(QPDF_Name::normalizeName(iter.first))
  113 + << "\": ";
  114 + }
  115 + }
  116 + iter.second.writeJSON(json_version, p);
  117 + }
  118 + }
  119 + p.writeEnd('}');
  120 +}
  121 +
94 122 bool
95 123 QPDF_Dictionary::hasKey(std::string const& key)
96 124 {
... ...
libqpdf/QPDF_InlineImage.cc
1 1 #include <qpdf/QPDF_InlineImage.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
  4 +
3 5 QPDF_InlineImage::QPDF_InlineImage(std::string const& val) :
4 6 QPDFValue(::ot_inlineimage, "inline-image"),
5 7 val(val)
... ... @@ -29,3 +31,9 @@ QPDF_InlineImage::getJSON(int json_version)
29 31 {
30 32 return JSON::makeNull();
31 33 }
  34 +
  35 +void
  36 +QPDF_InlineImage::writeJSON(int json_version, JSON::Writer& p)
  37 +{
  38 + p << "null";
  39 +}
... ...
libqpdf/QPDF_Integer.cc
1 1 #include <qpdf/QPDF_Integer.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QUtil.hh>
4 5  
5 6 QPDF_Integer::QPDF_Integer(long long val) :
... ... @@ -32,6 +33,12 @@ QPDF_Integer::getJSON(int json_version)
32 33 return JSON::makeInt(this->val);
33 34 }
34 35  
  36 +void
  37 +QPDF_Integer::writeJSON(int json_version, JSON::Writer& p)
  38 +{
  39 + p << std::to_string(this->val);
  40 +}
  41 +
35 42 long long
36 43 QPDF_Integer::getVal() const
37 44 {
... ...
libqpdf/QPDF_Name.cc
1 1 #include <qpdf/QPDF_Name.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QUtil.hh>
4 5  
5 6 QPDF_Name::QPDF_Name(std::string const& name) :
... ... @@ -68,3 +69,21 @@ QPDF_Name::getJSON(int json_version)
68 69 }
69 70 }
70 71 }
  72 +
  73 +void
  74 +QPDF_Name::writeJSON(int json_version, JSON::Writer& p)
  75 +{
  76 + if (json_version == 1) {
  77 + p << "\"" << JSON::Writer::encode_string(normalizeName(name)) << "\"";
  78 + } else {
  79 + bool has_8bit_chars;
  80 + bool is_valid_utf8;
  81 + bool is_utf16;
  82 + QUtil::analyze_encoding(this->name, has_8bit_chars, is_valid_utf8, is_utf16);
  83 + if (!has_8bit_chars || is_valid_utf8) {
  84 + p << "\"" << JSON::Writer::encode_string(name) << "\"";
  85 + } else {
  86 + p << "\"n:" << JSON::Writer::encode_string(normalizeName(name)) << "\"";
  87 + }
  88 + }
  89 +}
... ...
libqpdf/QPDF_Null.cc
1 1 #include <qpdf/QPDF_Null.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QPDFObject_private.hh>
4 5  
5 6 QPDF_Null::QPDF_Null() :
... ... @@ -49,3 +50,9 @@ QPDF_Null::getJSON(int json_version)
49 50 // If this is updated, QPDF_Array::getJSON must also be updated.
50 51 return JSON::makeNull();
51 52 }
  53 +
  54 +void
  55 +QPDF_Null::writeJSON(int json_version, JSON::Writer& p)
  56 +{
  57 + p << "null";
  58 +}
... ...
libqpdf/QPDF_Operator.cc
1 1 #include <qpdf/QPDF_Operator.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
  4 +
3 5 QPDF_Operator::QPDF_Operator(std::string const& val) :
4 6 QPDFValue(::ot_operator, "operator"),
5 7 val(val)
... ... @@ -29,3 +31,9 @@ QPDF_Operator::getJSON(int json_version)
29 31 {
30 32 return JSON::makeNull();
31 33 }
  34 +
  35 +void
  36 +QPDF_Operator::writeJSON(int json_version, JSON::Writer& p)
  37 +{
  38 + p << "null";
  39 +}
... ...
libqpdf/QPDF_Real.cc
1 1 #include <qpdf/QPDF_Real.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QUtil.hh>
4 5  
5 6 QPDF_Real::QPDF_Real(std::string const& val) :
... ... @@ -56,3 +57,18 @@ QPDF_Real::getJSON(int json_version)
56 57 }
57 58 return JSON::makeNumber(result);
58 59 }
  60 +
  61 +void
  62 +QPDF_Real::writeJSON(int json_version, JSON::Writer& p)
  63 +{
  64 + if (this->val.length() == 0) {
  65 + // Can't really happen...
  66 + p << "0";
  67 + } else if (this->val.at(0) == '.') {
  68 + p << "0" << this->val;
  69 + } else if (this->val.length() >= 2 && this->val.at(0) == '-' && this->val.at(1) == '.') {
  70 + p << "-0." << this->val.substr(2);
  71 + } else {
  72 + p << this->val;
  73 + }
  74 +}
... ...
libqpdf/QPDF_Reserved.cc
... ... @@ -32,3 +32,9 @@ QPDF_Reserved::getJSON(int json_version)
32 32 throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object");
33 33 return JSON::makeNull();
34 34 }
  35 +
  36 +void
  37 +QPDF_Reserved::writeJSON(int json_version, JSON::Writer& p)
  38 +{
  39 + throw std::logic_error("QPDFObjectHandle: attempting to get JSON from a reserved object");
  40 +}
... ...
libqpdf/QPDF_Stream.cc
1 1 #include <qpdf/QPDF_Stream.hh>
2 2  
3 3 #include <qpdf/ContentNormalizer.hh>
  4 +#include <qpdf/JSON_writer.hh>
4 5 #include <qpdf/Pipeline.hh>
5 6 #include <qpdf/Pl_Base64.hh>
6 7 #include <qpdf/Pl_Buffer.hh>
... ... @@ -185,6 +186,12 @@ QPDF_Stream::getJSON(int json_version)
185 186 return getStreamJSON(json_version, qpdf_sj_none, qpdf_dl_none, nullptr, "");
186 187 }
187 188  
  189 +void
  190 +QPDF_Stream::writeJSON(int json_version, JSON::Writer& p)
  191 +{
  192 + stream_dict.writeJSON(json_version, p);
  193 +}
  194 +
188 195 JSON
189 196 QPDF_Stream::getStreamJSON(
190 197 int json_version,
... ...
libqpdf/QPDF_String.cc
1 1 #include <qpdf/QPDF_String.hh>
2 2  
  3 +#include <qpdf/JSON_writer.hh>
3 4 #include <qpdf/QUtil.hh>
4 5  
5 6 // 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)
74 75 return JSON::makeString(result);
75 76 }
76 77  
  78 +void
  79 +QPDF_String::writeJSON(int json_version, JSON::Writer& p)
  80 +{
  81 + auto candidate = getUTF8Val();
  82 + if (json_version == 1) {
  83 +
  84 + p << "\"" << JSON::Writer::encode_string(candidate) << "\"";
  85 + } else {
  86 + // See if we can unambiguously represent as Unicode.
  87 + if (QUtil::is_utf16(this->val) || QUtil::is_explicit_utf8(this->val)) {
  88 + p << "\"u:" << JSON::Writer::encode_string(candidate) <<"\"";
  89 + return;
  90 + } else if (!useHexString()) {
  91 + std::string test;
  92 + if (QUtil::utf8_to_pdf_doc(candidate, test, '?') && (test == this->val)) {
  93 + // This is a PDF-doc string that can be losslessly encoded as Unicode.
  94 + p << "\"u:" << JSON::Writer::encode_string(candidate) <<"\"";
  95 + return;
  96 + }
  97 + }
  98 + p << "\"b:" << QUtil::hex_encode(val) <<"\"";
  99 + }
  100 +}
  101 +
77 102 bool
78 103 QPDF_String::useHexString() const
79 104 {
... ...
libqpdf/QPDF_Unresolved.cc
... ... @@ -33,3 +33,9 @@ QPDF_Unresolved::getJSON(int json_version)
33 33 throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle");
34 34 return JSON::makeNull();
35 35 }
  36 +
  37 +void
  38 +QPDF_Unresolved::writeJSON(int json_version, JSON::Writer& p)
  39 +{
  40 + throw std::logic_error("attempted to get JSON from an unresolved QPDFObjectHandle");
  41 +}
... ...
libqpdf/QPDF_json.cc
1 1 #include <qpdf/QPDF.hh>
2 2  
3 3 #include <qpdf/FileInputSource.hh>
  4 +#include <qpdf/JSON_writer.hh>
4 5 #include <qpdf/Pl_Base64.hh>
5 6 #include <qpdf/Pl_StdioFile.hh>
6 7 #include <qpdf/QIntC.hh>
... ... @@ -864,9 +865,15 @@ void
864 865 QPDF::writeJSONObject(
865 866 int version, Pipeline* p, bool& first, std::string const& key, QPDFObjectHandle& obj)
866 867 {
867   - auto j = JSON::makeDictionary();
868   - j.addDictionaryMember("value", obj.getJSON(version, true));
869   - JSON::writeDictionaryItem(p, first, key, j, 3);
  868 + if (first) {
  869 + *p << "\n \"" << key << "\": {\n \"value\": ";
  870 + first = false;
  871 + } else {
  872 + *p << ",\n \"" << key << "\": {\n \"value\": ";
  873 + }
  874 + auto w = JSON::Writer(p, 4);
  875 + obj.writeJSON(version, w, true);
  876 + *p << "\n }";
870 877 }
871 878  
872 879 void
... ...
libqpdf/qpdf/QPDFObject_private.hh
... ... @@ -38,6 +38,11 @@ class QPDFObject
38 38 {
39 39 return value->getJSON(json_version);
40 40 }
  41 + void
  42 + writeJSON(int json_version, JSON::Writer& p)
  43 + {
  44 + return value->writeJSON(json_version, p);
  45 + }
41 46 std::string
42 47 getStringValue() const
43 48 {
... ...
libqpdf/qpdf/QPDFValue.hh
... ... @@ -25,6 +25,7 @@ class QPDFValue: public std::enable_shared_from_this&lt;QPDFValue&gt;
25 25 virtual std::shared_ptr<QPDFObject> copy(bool shallow = false) = 0;
26 26 virtual std::string unparse() = 0;
27 27 virtual JSON getJSON(int json_version) = 0;
  28 + virtual void writeJSON(int json_version, JSON::Writer& p) = 0;
28 29  
29 30 struct JSON_Descr
30 31 {
... ...
libqpdf/qpdf/QPDF_Array.hh
... ... @@ -23,6 +23,7 @@ class QPDF_Array: public QPDFValue
23 23 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
24 24 std::string unparse() override;
25 25 JSON getJSON(int json_version) override;
  26 + void writeJSON(int json_version, JSON::Writer& p) override;
26 27 void disconnect() override;
27 28  
28 29 int
... ...
libqpdf/qpdf/QPDF_Bool.hh
... ... @@ -11,6 +11,8 @@ class QPDF_Bool: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
  15 +
14 16 bool getVal() const;
15 17  
16 18 private:
... ...
libqpdf/qpdf/QPDF_Destroyed.hh
... ... @@ -10,6 +10,7 @@ class QPDF_Destroyed: public QPDFValue
10 10 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
11 11 std::string unparse() override;
12 12 JSON getJSON(int json_version) override;
  13 + void writeJSON(int json_version, JSON::Writer& p) override;
13 14 static std::shared_ptr<QPDFValue> getInstance();
14 15  
15 16 private:
... ...
libqpdf/qpdf/QPDF_Dictionary.hh
... ... @@ -17,6 +17,7 @@ class QPDF_Dictionary: public QPDFValue
17 17 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
18 18 std::string unparse() override;
19 19 JSON getJSON(int json_version) override;
  20 + void writeJSON(int json_version, JSON::Writer& p) override;
20 21 void disconnect() override;
21 22  
22 23 // hasKey() and getKeys() treat keys with null values as if they aren't there. getKey() returns
... ...
libqpdf/qpdf/QPDF_InlineImage.hh
... ... @@ -11,6 +11,7 @@ class QPDF_InlineImage: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15 std::string
15 16 getStringValue() const override
16 17 {
... ...
libqpdf/qpdf/QPDF_Integer.hh
... ... @@ -11,6 +11,7 @@ class QPDF_Integer: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15 long long getVal() const;
15 16  
16 17 private:
... ...
libqpdf/qpdf/QPDF_Name.hh
... ... @@ -11,6 +11,7 @@ class QPDF_Name: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15  
15 16 // Put # into strings with characters unsuitable for name token
16 17 static std::string normalizeName(std::string const& name);
... ...
libqpdf/qpdf/QPDF_Null.hh
... ... @@ -19,6 +19,7 @@ class QPDF_Null: public QPDFValue
19 19 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
20 20 std::string unparse() override;
21 21 JSON getJSON(int json_version) override;
  22 + void writeJSON(int json_version, JSON::Writer& p) override;
22 23  
23 24 private:
24 25 QPDF_Null();
... ...
libqpdf/qpdf/QPDF_Operator.hh
... ... @@ -11,6 +11,7 @@ class QPDF_Operator: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15 std::string
15 16 getStringValue() const override
16 17 {
... ...
libqpdf/qpdf/QPDF_Real.hh
... ... @@ -13,6 +13,7 @@ class QPDF_Real: public QPDFValue
13 13 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
14 14 std::string unparse() override;
15 15 JSON getJSON(int json_version) override;
  16 + void writeJSON(int json_version, JSON::Writer& p) override;
16 17 std::string
17 18 getStringValue() const override
18 19 {
... ...
libqpdf/qpdf/QPDF_Reserved.hh
... ... @@ -11,6 +11,7 @@ class QPDF_Reserved: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15  
15 16 private:
16 17 QPDF_Reserved();
... ...
libqpdf/qpdf/QPDF_Stream.hh
... ... @@ -26,6 +26,7 @@ class QPDF_Stream: public QPDFValue
26 26 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
27 27 std::string unparse() override;
28 28 JSON getJSON(int json_version) override;
  29 + void writeJSON(int json_version, JSON::Writer& p) override;
29 30 void setDescription(
30 31 QPDF*, std::shared_ptr<QPDFValue::Description>& description, qpdf_offset_t offset) override;
31 32 void disconnect() override;
... ...
libqpdf/qpdf/QPDF_String.hh
... ... @@ -17,6 +17,7 @@ class QPDF_String: public QPDFValue
17 17 std::string unparse() override;
18 18 std::string unparse(bool force_binary);
19 19 JSON getJSON(int json_version) override;
  20 + void writeJSON(int json_version, JSON::Writer& p) override;
20 21 std::string getUTF8Val() const;
21 22 std::string
22 23 getStringValue() const override
... ...
libqpdf/qpdf/QPDF_Unresolved.hh
... ... @@ -11,6 +11,7 @@ class QPDF_Unresolved: public QPDFValue
11 11 std::shared_ptr<QPDFObject> copy(bool shallow = false) override;
12 12 std::string unparse() override;
13 13 JSON getJSON(int json_version) override;
  14 + void writeJSON(int json_version, JSON::Writer& p) override;
14 15  
15 16 private:
16 17 QPDF_Unresolved(QPDF* qpdf, QPDFObjGen const& og);
... ...