11#include <private/qnumeric_p.h>
13#include <private/qtools_p.h>
17using namespace Qt::StringLiterals;
20class DiagnosticNotation
23 static QString create(
const QCborValue &v, QCborValue::DiagnosticNotationOptions opts)
25 DiagnosticNotation dn(opts);
31 QStack<
int> byteArrayFormatStack;
34 QCborValue::DiagnosticNotationOptions opts;
38 enum { IndentationWidth = 4 };
39 DiagnosticNotation *dn;
40 Nest(DiagnosticNotation *that) : dn(that)
43 static const char indent[IndentationWidth + 1] =
" ";
44 if (dn->opts & QCborValue::LineWrapped)
45 dn->separator += QLatin1StringView(indent, IndentationWidth);
50 if (dn->opts & QCborValue::LineWrapped)
51 dn->separator.chop(IndentationWidth);
55 DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
56 : separator(opts_ & QCborValue::LineWrapped ?
"\n"_L1 :
""_L1), opts(opts_)
58 byteArrayFormatStack.push(
int(QCborKnownTags::ExpectedBase16));
61 void appendString(
const QString &s);
62 void appendArray(
const QCborArray &a);
63 void appendMap(
const QCborMap &m);
64 void appendValue(
const QCborValue &v);
73 s = (d < 0) ? QStringLiteral(
"-inf") : QStringLiteral(
"inf");
74 }
else if (qt_is_nan(d)) {
75 s = QStringLiteral(
"nan");
76 }
else if (convertDoubleTo(d, &v)) {
77 s = QString::fromLatin1(
"%1.0").arg(v);
81 s = QString::number(d,
'g', QLocale::FloatingPointShortest);
82 if (!s.contains(u'.') && !s.contains(u'e'))
90 switch (quint64(tag)) {
91 case quint64(QCborKnownTags::ExpectedBase16):
92 case quint64(QCborKnownTags::ExpectedBase64):
93 case quint64(QCborKnownTags::ExpectedBase64url):
99void DiagnosticNotation::appendString(
const QString &s)
103 const QChar *begin = s.begin();
104 const QChar *end = s.end();
105 while (begin < end) {
107 const QChar *ptr = begin;
108 for ( ; ptr < end; ++ptr) {
109 ushort uc = ptr->unicode();
110 if (uc ==
'\\' || uc ==
'"' || uc <
' ' || uc >= 0x7f)
115 result.append(begin, ptr - begin);
121 static const char escapeMap[16] = {
132 buf[1] = QChar::Null;
133 char16_t uc = ptr->unicode();
135 if (uc <
sizeof(escapeMap))
136 buf[1] = QLatin1Char(escapeMap[uc]);
137 else if (uc ==
'"' || uc ==
'\\')
140 if (buf[1] == QChar::Null) {
141 const auto toHexUpper = [](
char32_t value) -> QChar {
143 return char16_t(QtMiscUtils::toHexUpper(value));
145 if (ptr->isHighSurrogate() && (ptr + 1) != end && ptr[1].isLowSurrogate()) {
148 char32_t ucs4 = QChar::surrogateToUcs4(uc, ptr->unicode());
152 buf[4] = toHexUpper(ucs4 >> 20);
153 buf[5] = toHexUpper(ucs4 >> 16);
154 buf[6] = toHexUpper(ucs4 >> 12);
155 buf[7] = toHexUpper(ucs4 >> 8);
156 buf[8] = toHexUpper(ucs4 >> 4);
157 buf[9] = toHexUpper(ucs4);
161 buf[2] = toHexUpper(uc >> 12);
162 buf[3] = toHexUpper(uc >> 8);
163 buf[4] = toHexUpper(uc >> 4);
164 buf[5] = toHexUpper(uc);
169 result.append(buf, buflen);
176void DiagnosticNotation::appendArray(
const QCborArray &a)
181 QLatin1StringView commaValue(
", ", opts & QCborValue::LineWrapped ? 1 : 2);
184 QLatin1StringView comma;
186 result += comma + separator;
192 result += separator + u']';
195void DiagnosticNotation::appendMap(
const QCborMap &m)
200 QLatin1StringView commaValue(
", ", opts & QCborValue::LineWrapped ? 1 : 2);
203 QLatin1StringView comma;
205 result += comma + separator;
207 appendValue(v.first);
209 appendValue(v.second);
213 result += separator + u'}';
216void DiagnosticNotation::appendValue(
const QCborValue &v)
219 case QCborValue::Integer:
220 result += QString::number(v.toInteger());
222 case QCborValue::ByteArray:
223 switch (byteArrayFormatStack.top()) {
224 case int(QCborKnownTags::ExpectedBase16):
225 result += QString::fromLatin1(
"h'" +
226 v.toByteArray().toHex(opts & QCborValue::ExtendedFormat ?
' ' :
'\0') +
229 case int(QCborKnownTags::ExpectedBase64):
230 result += QString::fromLatin1(
"b64'" + v.toByteArray().toBase64() +
'\'');
233 case int(QCborKnownTags::ExpectedBase64url):
234 result += QString::fromLatin1(
"b64'" +
235 v.toByteArray().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals) +
239 case QCborValue::String:
240 return appendString(v.toString());
241 case QCborValue::Array:
242 return appendArray(v.toArray());
243 case QCborValue::Map:
244 return appendMap(v.toMap());
245 case QCborValue::False:
246 result +=
"false"_L1;
248 case QCborValue::True:
251 case QCborValue::Null:
254 case QCborValue::Undefined:
255 result +=
"undefined"_L1;
257 case QCborValue::Double:
258 result += makeFpString(v.toDouble());
260 case QCborValue::Invalid:
261 result += QStringLiteral(
"<invalid>");
272 bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
274 byteArrayFormatStack.push(
int(v.tag()));
275 result += QString::number(quint64(v.tag())) + u'(';
276 appendValue(v.taggedValue());
279 byteArrayFormatStack.pop();
282 result += QString::fromLatin1(
"simple(%1)").arg(quint8(v.toSimpleType()));
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312QString QCborValue::toDiagnosticNotation(DiagnosticNotationOptions opts)
const
314 return DiagnosticNotation::create(*
this, opts);
static QString makeFpString(double d)
static bool isByteArrayEncodingTag(QCborTag tag)