diff options
Diffstat (limited to 'libqpdf')
-rw-r--r-- | libqpdf/JSON.cc | 130 | ||||
-rw-r--r-- | libqpdf/QPDFTokenizer.cc | 8 | ||||
-rw-r--r-- | libqpdf/QPDF_Name.cc | 5 |
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; |