aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/JSON.cc130
-rw-r--r--libqpdf/QPDFTokenizer.cc8
-rw-r--r--libqpdf/QPDF_Name.cc5
3 files changed, 86 insertions, 57 deletions
diff --git a/libqpdf/JSON.cc b/libqpdf/JSON.cc
index 1dc09013..76db652b 100644
--- a/libqpdf/JSON.cc
+++ b/libqpdf/JSON.cc
@@ -125,6 +125,7 @@ JSON::JSON_array::write(Pipeline* p, size_t depth) const
}
JSON::JSON_string::JSON_string(std::string const& utf8) :
+ JSON_value(vt_string),
utf8(utf8),
encoded(encode_string(utf8))
{
@@ -137,16 +138,19 @@ JSON::JSON_string::write(Pipeline* p, size_t) const
}
JSON::JSON_number::JSON_number(long long value) :
+ JSON_value(vt_number),
encoded(std::to_string(value))
{
}
JSON::JSON_number::JSON_number(double value) :
+ JSON_value(vt_number),
encoded(QUtil::double_to_string(value, 6))
{
}
JSON::JSON_number::JSON_number(std::string const& value) :
+ JSON_value(vt_number),
encoded(value)
{
}
@@ -158,6 +162,7 @@ JSON::JSON_number::write(Pipeline* p, size_t) const
}
JSON::JSON_bool::JSON_bool(bool val) :
+ JSON_value(vt_bool),
value(val)
{
}
@@ -175,6 +180,7 @@ JSON::JSON_null::write(Pipeline* p, size_t) const
}
JSON::JSON_blob::JSON_blob(std::function<void(Pipeline*)> fn) :
+ JSON_value(vt_blob),
fn(fn)
{
}
@@ -212,41 +218,61 @@ JSON::unparse() const
std::string
JSON::encode_string(std::string const& str)
{
- std::string result;
- size_t len = str.length();
- for (size_t i = 0; i < len; ++i) {
- unsigned char ch = static_cast<unsigned char>(str.at(i));
- switch (ch) {
- case '\\':
- result += "\\\\";
- break;
- case '\"':
- result += "\\\"";
- break;
- case '\b':
- result += "\\b";
- break;
- case '\f':
- result += "\\f";
- break;
- case '\n':
- result += "\\n";
- break;
- case '\r':
- result += "\\r";
- break;
- case '\t':
- result += "\\t";
- break;
- default:
- if (ch < 32) {
- result += "\\u" + QUtil::int_to_string_base(ch, 16, 4);
- } else {
- result.append(1, static_cast<char>(ch));
+ static auto constexpr hexchars = "0123456789abcdef";
+
+ auto begin = str.cbegin();
+ auto end = str.cend();
+ auto iter = begin;
+ while (iter != end) {
+ auto c = static_cast<unsigned char>(*iter);
+ if ((c > 34 && c != '\\') || c == ' ' || c == 33) {
+ // Optimistically check that no char in str requires escaping.
+ // Hopefully we can just return the input str.
+ ++iter;
+ } else {
+ // We found a char that requires escaping. Initialize result to the
+ // chars scanned so far, append/replace the rest of str one char at
+ // a time, and return the result.
+ std::string result{begin, iter};
+
+ for (; iter != end; ++iter) {
+ auto ch = static_cast<unsigned char>(*iter);
+ if ((ch > 34 && ch != '\\') || ch == ' ' || ch == 33) {
+ // Check for most common case first.
+ result += *iter;
+ } else {
+ switch (ch) {
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ default:
+ result += ch < 16 ? "\\u000" : "\\u001";
+ result += hexchars[ch % 16];
+ }
+ }
}
+ return result;
}
}
- return result;
+ return str;
}
JSON
@@ -348,56 +374,52 @@ JSON::makeBlob(std::function<void(Pipeline*)> fn)
bool
JSON::isArray() const
{
- return nullptr != dynamic_cast<JSON_array const*>(this->m->value.get());
+ return m->value->type_code == vt_array;
}
bool
JSON::isDictionary() const
{
- return nullptr !=
- dynamic_cast<JSON_dictionary const*>(this->m->value.get());
+ return m->value->type_code == vt_dictionary;
}
bool
JSON::getString(std::string& utf8) const
{
- auto v = dynamic_cast<JSON_string const*>(this->m->value.get());
- if (v == nullptr) {
- return false;
+ if (m->value->type_code == vt_string) {
+ auto v = dynamic_cast<JSON_string const*>(this->m->value.get());
+ utf8 = v->utf8;
+ return true;
}
- utf8 = v->utf8;
- return true;
+ return false;
}
bool
JSON::getNumber(std::string& value) const
{
- auto v = dynamic_cast<JSON_number const*>(this->m->value.get());
- if (v == nullptr) {
- return false;
+ if (m->value->type_code == vt_number) {
+ auto v = dynamic_cast<JSON_number const*>(this->m->value.get());
+ value = v->encoded;
+ return true;
}
- value = v->encoded;
- return true;
+ return false;
}
bool
JSON::getBool(bool& value) const
{
- auto v = dynamic_cast<JSON_bool const*>(this->m->value.get());
- if (v == nullptr) {
- return false;
+ if (m->value->type_code == vt_bool) {
+ auto v = dynamic_cast<JSON_bool const*>(this->m->value.get());
+ value = v->value;
+ return true;
}
- value = v->value;
- return true;
+ return false;
}
bool
JSON::isNull() const
{
- if (dynamic_cast<JSON_null const*>(this->m->value.get())) {
- return true;
- }
- return false;
+ return m->value->type_code == vt_null;
}
bool
diff --git a/libqpdf/QPDFTokenizer.cc b/libqpdf/QPDFTokenizer.cc
index fe36d768..990d5b65 100644
--- a/libqpdf/QPDFTokenizer.cc
+++ b/libqpdf/QPDFTokenizer.cc
@@ -14,10 +14,14 @@
#include <stdlib.h>
#include <string.h>
-static bool
+static inline bool
is_delimiter(char ch)
{
- return (strchr(" \t\n\v\f\r()<>[]{}/%", ch) != nullptr);
+ return (
+ ch == ' ' || ch == '\n' || ch == '/' || ch == '(' || ch == ')' ||
+ ch == '{' || ch == '}' || ch == '<' || ch == '>' || ch == '[' ||
+ ch == ']' || ch == '%' || ch == '\t' || ch == '\r' || ch == '\v' ||
+ ch == '\f' || ch == 0);
}
namespace
diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc
index 1587bcf4..3241ec1c 100644
--- a/libqpdf/QPDF_Name.cc
+++ b/libqpdf/QPDF_Name.cc
@@ -37,7 +37,10 @@ QPDF_Name::normalizeName(std::string const& name)
// QPDFTokenizer embeds a null character to encode an
// invalid #.
result += "#";
- } else if (strchr("#()<>[]{}/%", ch) || (ch < 33) || (ch > 126)) {
+ } else if (
+ ch < 33 || ch == '/' || ch == '(' || ch == ')' || ch == '{' ||
+ ch == '}' || ch == '<' || ch == '>' || ch == '[' || ch == ']' ||
+ ch == '%' || ch > 126) {
result += QUtil::hex_encode_char(ch);
} else {
result += ch;