diff options
author | Jay Berkenbilt <ejb@ql.org> | 2024-02-17 20:15:48 +0100 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2024-02-17 20:15:48 +0100 |
commit | e362bce8e86f4912eaa008bac06f9e2c19b72d3f (patch) | |
tree | 42fcd9eed699714f98ddee634763e4d670a2652b /libqpdf/QPDF_Name.cc | |
parent | 5a29b7f9dd353c7baf2ca738bd2a56582a6525ea (diff) | |
parent | 413aba5bf2ef239d3abf024de3c819e153171035 (diff) | |
download | qpdf-e362bce8e86f4912eaa008bac06f9e2c19b72d3f.tar.zst |
Merge branch 'jw' from #1146 into work
Diffstat (limited to 'libqpdf/QPDF_Name.cc')
-rw-r--r-- | libqpdf/QPDF_Name.cc | 74 |
1 files changed, 64 insertions, 10 deletions
diff --git a/libqpdf/QPDF_Name.cc b/libqpdf/QPDF_Name.cc index 5fde9c65..0e7f441a 100644 --- a/libqpdf/QPDF_Name.cc +++ b/libqpdf/QPDF_Name.cc @@ -1,7 +1,10 @@ #include <qpdf/QPDF_Name.hh> +#include <qpdf/JSON_writer.hh> #include <qpdf/QUtil.hh> +#include <string_view> + QPDF_Name::QPDF_Name(std::string const& name) : QPDFValue(::ot_name, "name"), name(name) @@ -51,20 +54,71 @@ QPDF_Name::unparse() return normalizeName(this->name); } -JSON -QPDF_Name::getJSON(int json_version) +std::pair<bool, bool> +QPDF_Name::analyzeJSONEncoding(const std::string& name) +{ + std::basic_string_view<unsigned char> view{ + reinterpret_cast<const unsigned char*>(name.data()), name.size()}; + + int tail = 0; // Number of continuation characters expected. + bool tail2 = false; // Potential overlong 3 octet utf-8. + bool tail3 = false; // potential overlong 4 octet + bool needs_escaping = false; + for (auto const& c: view) { + if (tail) { + if ((c & 0xc0) != 0x80) { + return {false, false}; + } + if (tail2) { + if ((c & 0xe0) == 0x80) { + return {false, false}; + } + tail2 = false; + } else if (tail3) { + if ((c & 0xf0) == 0x80) { + return {false, false}; + } + tail3 = false; + } + tail--; + } else if (c < 0x80) { + if (!needs_escaping) { + needs_escaping = !((c > 34 && c != '\\') || c == ' ' || c == 33); + } + } else if ((c & 0xe0) == 0xc0) { + if ((c & 0xfe) == 0xc0) { + return {false, false}; + } + tail = 1; + } else if ((c & 0xf0) == 0xe0) { + tail2 = (c == 0xe0); + tail = 2; + } else if ((c & 0xf8) == 0xf0) { + tail3 = (c == 0xf0); + tail = 3; + } else { + return {false, false}; + } + } + return {tail == 0, !needs_escaping}; +} + +void +QPDF_Name::writeJSON(int json_version, JSON::Writer& p) { + // For performance reasons this code is duplicated in QPDF_Dictionary::writeJSON. When updating + // this method make sure QPDF_Dictionary is also update. if (json_version == 1) { - return JSON::makeString(normalizeName(this->name)); + 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) { - return JSON::makeString(this->name); + if (auto res = analyzeJSONEncoding(name); res.first) { + if (res.second) { + p << "\"" << name << "\""; + } else { + p << "\"" << JSON::Writer::encode_string(name) << "\""; + } } else { - return JSON::makeString("n:" + normalizeName(this->name)); + p << "\"n:" << JSON::Writer::encode_string(normalizeName(name)) << "\""; } } } |