2008-04-29 12:55:25 +00:00
|
|
|
#include <qpdf/QPDF_String.hh>
|
|
|
|
|
2008-11-23 18:49:13 +00:00
|
|
|
#include <qpdf/QTC.hh>
|
2022-04-02 21:14:10 +00:00
|
|
|
#include <qpdf/QUtil.hh>
|
2008-11-23 18:49:13 +00:00
|
|
|
|
2008-04-29 12:55:25 +00:00
|
|
|
// DO NOT USE ctype -- it is locale dependent for some things, and
|
|
|
|
// it's not worth the risk of including it in case it may accidentally
|
|
|
|
// be used.
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
// See above about ctype.
|
2022-04-02 21:14:10 +00:00
|
|
|
static bool
|
|
|
|
is_ascii_printable(char ch)
|
2009-10-17 17:31:52 +00:00
|
|
|
{
|
|
|
|
return ((ch >= 32) && (ch <= 126));
|
|
|
|
}
|
2022-04-02 21:14:10 +00:00
|
|
|
static bool
|
|
|
|
is_iso_latin1_printable(char ch)
|
2008-04-29 12:55:25 +00:00
|
|
|
{
|
2022-04-02 21:14:10 +00:00
|
|
|
return (
|
|
|
|
((ch >= 32) && (ch <= 126)) || (static_cast<unsigned char>(ch) >= 160));
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QPDF_String::QPDF_String(std::string const& val) :
|
|
|
|
val(val)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-01-05 17:54:41 +00:00
|
|
|
QPDF_String*
|
|
|
|
QPDF_String::new_utf16(std::string const& utf8_val)
|
|
|
|
{
|
2021-01-23 22:58:23 +00:00
|
|
|
std::string result;
|
2022-04-02 21:14:10 +00:00
|
|
|
if (!QUtil::utf8_to_pdf_doc(utf8_val, result, '?')) {
|
2021-01-23 22:58:23 +00:00
|
|
|
result = QUtil::utf8_to_utf16(utf8_val);
|
|
|
|
}
|
|
|
|
return new QPDF_String(result);
|
2018-06-21 18:03:45 +00:00
|
|
|
}
|
|
|
|
|
2008-04-29 12:55:25 +00:00
|
|
|
std::string
|
|
|
|
QPDF_String::unparse()
|
|
|
|
{
|
|
|
|
return unparse(false);
|
|
|
|
}
|
|
|
|
|
2018-12-17 22:40:29 +00:00
|
|
|
JSON
|
2022-05-07 11:53:45 +00:00
|
|
|
QPDF_String::getJSON(int json_version)
|
2018-12-17 22:40:29 +00:00
|
|
|
{
|
2022-05-07 12:20:09 +00:00
|
|
|
if (json_version == 1) {
|
|
|
|
return JSON::makeString(getUTF8Val());
|
|
|
|
}
|
|
|
|
// See if we can unambiguously represent as Unicode.
|
|
|
|
bool is_unicode = false;
|
|
|
|
std::string result;
|
|
|
|
std::string candidate = getUTF8Val();
|
|
|
|
if (QUtil::is_utf16(this->val) || QUtil::is_explicit_utf8(this->val)) {
|
|
|
|
is_unicode = true;
|
|
|
|
result = candidate;
|
|
|
|
} 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.
|
|
|
|
is_unicode = true;
|
|
|
|
result = candidate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (is_unicode) {
|
|
|
|
result = "u:" + result;
|
|
|
|
} else {
|
|
|
|
result = "b:" + QUtil::hex_encode(this->val);
|
|
|
|
}
|
|
|
|
return JSON::makeString(result);
|
2018-12-17 22:40:29 +00:00
|
|
|
}
|
|
|
|
|
2013-01-22 14:57:07 +00:00
|
|
|
QPDFObject::object_type_e
|
|
|
|
QPDF_String::getTypeCode() const
|
|
|
|
{
|
|
|
|
return QPDFObject::ot_string;
|
|
|
|
}
|
|
|
|
|
|
|
|
char const*
|
|
|
|
QPDF_String::getTypeName() const
|
|
|
|
{
|
|
|
|
return "string";
|
|
|
|
}
|
|
|
|
|
2022-05-07 12:20:09 +00:00
|
|
|
bool
|
|
|
|
QPDF_String::useHexString() const
|
2008-04-29 12:55:25 +00:00
|
|
|
{
|
2022-05-07 12:20:09 +00:00
|
|
|
// Heuristic: use the hexadecimal representation of a string if
|
|
|
|
// there are any non-printable (in PDF Doc encoding) characters or
|
|
|
|
// if too large of a proportion of the string consists of
|
|
|
|
// non-ASCII characters.
|
|
|
|
bool nonprintable = false;
|
|
|
|
unsigned int non_ascii = 0;
|
|
|
|
for (unsigned int i = 0; i < this->val.length(); ++i) {
|
|
|
|
char ch = this->val.at(i);
|
|
|
|
if ((ch == 0) ||
|
|
|
|
(!(is_ascii_printable(ch) || strchr("\n\r\t\b\f", ch)))) {
|
|
|
|
if ((ch >= 0) && (ch < 24)) {
|
|
|
|
nonprintable = true;
|
2022-02-08 14:18:08 +00:00
|
|
|
}
|
2022-05-07 12:20:09 +00:00
|
|
|
++non_ascii;
|
2022-02-08 14:18:08 +00:00
|
|
|
}
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
2022-05-07 12:20:09 +00:00
|
|
|
return (nonprintable || (5 * non_ascii > val.length()));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
QPDF_String::unparse(bool force_binary)
|
|
|
|
{
|
|
|
|
bool use_hexstring = force_binary || useHexString();
|
2008-04-29 12:55:25 +00:00
|
|
|
std::string result;
|
2022-04-02 21:14:10 +00:00
|
|
|
if (use_hexstring) {
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "<" + QUtil::hex_encode(this->val) + ">";
|
2022-04-02 21:14:10 +00:00
|
|
|
} else {
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "(";
|
2022-04-02 21:14:10 +00:00
|
|
|
for (unsigned int i = 0; i < this->val.length(); ++i) {
|
2022-02-08 14:18:08 +00:00
|
|
|
char ch = this->val.at(i);
|
2022-04-02 21:14:10 +00:00
|
|
|
switch (ch) {
|
|
|
|
case '\n':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\n";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '\r':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\r";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '\t':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\t";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '\b':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\b";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '\f':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\f";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '(':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\(";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case ')':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\)";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
case '\\':
|
2022-02-08 14:18:08 +00:00
|
|
|
result += "\\\\";
|
|
|
|
break;
|
|
|
|
|
2022-04-02 21:14:10 +00:00
|
|
|
default:
|
|
|
|
if (is_iso_latin1_printable(ch)) {
|
2022-02-08 14:18:08 +00:00
|
|
|
result += this->val.at(i);
|
2022-04-02 21:14:10 +00:00
|
|
|
} else {
|
|
|
|
result +=
|
|
|
|
"\\" +
|
|
|
|
QUtil::int_to_string_base(
|
|
|
|
static_cast<int>(static_cast<unsigned char>(ch)),
|
|
|
|
8,
|
|
|
|
3);
|
2022-02-08 14:18:08 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result += ")";
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
QPDF_String::getVal() const
|
|
|
|
{
|
|
|
|
return this->val;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
QPDF_String::getUTF8Val() const
|
|
|
|
{
|
2022-04-02 21:14:10 +00:00
|
|
|
if (QUtil::is_utf16(this->val)) {
|
2019-01-13 13:00:14 +00:00
|
|
|
return QUtil::utf16_to_utf8(this->val);
|
2022-04-23 20:39:27 +00:00
|
|
|
} else if (QUtil::is_explicit_utf8(this->val)) {
|
2022-02-22 13:04:11 +00:00
|
|
|
// PDF 2.0 allows UTF-8 strings when explicitly prefixed with
|
2022-04-23 20:39:27 +00:00
|
|
|
// the three-byte representation of U+FEFF.
|
2022-02-22 13:04:11 +00:00
|
|
|
return this->val.substr(3);
|
2022-04-02 21:14:10 +00:00
|
|
|
} else {
|
2019-01-13 13:00:14 +00:00
|
|
|
return QUtil::pdf_doc_to_utf8(this->val);
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
|
|
|
}
|