Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qcbordiagnostic.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 Intel Corporation.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcborvalue.h"
5#include "qcborvalue_p.h"
6
7#include "qcborarray.h"
8#include "qcbormap.h"
9
10#include <private/qnumeric_p.h>
11#include <qstack.h>
12#include <private/qtools_p.h>
13
15
16using namespace Qt::StringLiterals;
17
18namespace {
19class DiagnosticNotation
20{
21public:
22 static QString create(const QCborValue &v, QCborValue::DiagnosticNotationOptions opts)
23 {
24 DiagnosticNotation dn(opts);
25 dn.appendValue(v);
26 return dn.result;
27 }
28
29private:
30 QStack<int> byteArrayFormatStack;
31 QString separator;
33 QCborValue::DiagnosticNotationOptions opts;
34 int nestingLevel = 0;
35
36 struct Nest {
37 enum { IndentationWidth = 4 };
38 DiagnosticNotation *dn;
39 Nest(DiagnosticNotation *that) : dn(that)
40 {
41 ++dn->nestingLevel;
42 static const char indent[IndentationWidth + 1] = " ";
43 if (dn->opts & QCborValue::LineWrapped)
44 dn->separator += QLatin1StringView(indent, IndentationWidth);
45 }
46 ~Nest()
47 {
48 --dn->nestingLevel;
49 if (dn->opts & QCborValue::LineWrapped)
50 dn->separator.chop(IndentationWidth);
51 }
52 };
53
54 DiagnosticNotation(QCborValue::DiagnosticNotationOptions opts_)
55 : separator(opts_ & QCborValue::LineWrapped ? "\n"_L1 : ""_L1), opts(opts_)
56 {
57 byteArrayFormatStack.push(int(QCborKnownTags::ExpectedBase16));
58 }
59
60 void appendString(const QString &s);
61 void appendArray(const QCborArray &a);
62 void appendMap(const QCborMap &m);
63 void appendValue(const QCborValue &v);
64};
65}
66
67static QString makeFpString(double d)
68{
69 QString s;
70 quint64 v;
71 if (qt_is_inf(d)) {
72 s = (d < 0) ? QStringLiteral("-inf") : QStringLiteral("inf");
73 } else if (qt_is_nan(d)) {
74 s = QStringLiteral("nan");
75 } else if (convertDoubleTo(d, &v)) {
76 s = QString::fromLatin1("%1.0").arg(v);
77 if (d < 0)
78 s.prepend(u'-');
79 } else {
81 if (!s.contains(u'.') && !s.contains(u'e'))
82 s += u'.';
83 }
84 return s;
85}
86
88{
89 switch (quint64(tag)) {
93 return true;
94 }
95 return false;
96}
97
98void DiagnosticNotation::appendString(const QString &s)
99{
100 result += u'"';
101
102 const QChar *begin = s.begin();
103 const QChar *end = s.end();
104 while (begin < end) {
105 // find the longest span comprising only non-escaped characters
106 const QChar *ptr = begin;
107 for ( ; ptr < end; ++ptr) {
108 ushort uc = ptr->unicode();
109 if (uc == '\\' || uc == '"' || uc < ' ' || uc >= 0x7f)
110 break;
111 }
112
113 if (ptr != begin)
114 result.append(begin, ptr - begin);
115
116 if (ptr == end)
117 break;
118
119 // there's an escaped character
120 static const char escapeMap[16] = {
121 // The C escape characters \a \b \t \n \v \f and \r indexed by
122 // their ASCII values
123 0, 0, 0, 0,
124 0, 0, 0, 'a',
125 'b', 't', 'n', 'v',
126 'f', 'r', 0, 0
127 };
128 int buflen = 2;
129 QChar buf[10];
130 buf[0] = u'\\';
131 buf[1] = QChar::Null;
132 char16_t uc = ptr->unicode();
133
134 if (uc < sizeof(escapeMap))
135 buf[1] = QLatin1Char(escapeMap[uc]);
136 else if (uc == '"' || uc == '\\')
137 buf[1] = QChar(uc);
138
139 if (buf[1] == QChar::Null) {
140 const auto toHexUpper = [](char32_t value) -> QChar {
141 // QtMiscUtils::toHexUpper() returns char, we need QChar, so wrap
142 return char16_t(QtMiscUtils::toHexUpper(value));
143 };
144 if (ptr->isHighSurrogate() && (ptr + 1) != end && ptr[1].isLowSurrogate()) {
145 // properly-paired surrogates
146 ++ptr;
147 char32_t ucs4 = QChar::surrogateToUcs4(uc, ptr->unicode());
148 buf[1] = u'U';
149 buf[2] = u'0'; // toHexUpper(ucs4 >> 28);
150 buf[3] = u'0'; // toHexUpper(ucs4 >> 24);
151 buf[4] = toHexUpper(ucs4 >> 20);
152 buf[5] = toHexUpper(ucs4 >> 16);
153 buf[6] = toHexUpper(ucs4 >> 12);
154 buf[7] = toHexUpper(ucs4 >> 8);
155 buf[8] = toHexUpper(ucs4 >> 4);
156 buf[9] = toHexUpper(ucs4);
157 buflen = 10;
158 } else {
159 buf[1] = u'u';
160 buf[2] = toHexUpper(uc >> 12);
161 buf[3] = toHexUpper(uc >> 8);
162 buf[4] = toHexUpper(uc >> 4);
163 buf[5] = toHexUpper(uc);
164 buflen = 6;
165 }
166 }
167
168 result.append(buf, buflen);
169 begin = ptr + 1;
170 }
171
172 result += u'"';
173}
174
175void DiagnosticNotation::appendArray(const QCborArray &a)
176{
177 result += u'[';
178
179 // length 2 (including the space) when not line wrapping
180 QLatin1StringView commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
181 {
182 Nest n(this);
183 QLatin1StringView comma;
184 for (auto v : a) {
185 result += comma + separator;
186 comma = commaValue;
187 appendValue(v);
188 }
189 }
190
191 result += separator + u']';
192}
193
194void DiagnosticNotation::appendMap(const QCborMap &m)
195{
196 result += u'{';
197
198 // length 2 (including the space) when not line wrapping
199 QLatin1StringView commaValue(", ", opts & QCborValue::LineWrapped ? 1 : 2);
200 {
201 Nest n(this);
202 QLatin1StringView comma;
203 for (auto v : m) {
204 result += comma + separator;
205 comma = commaValue;
206 appendValue(v.first);
207 result += ": "_L1;
208 appendValue(v.second);
209 }
210 }
211
212 result += separator + u'}';
213};
214
215void DiagnosticNotation::appendValue(const QCborValue &v)
216{
217 switch (v.type()) {
219 result += QString::number(v.toInteger());
220 return;
222 switch (byteArrayFormatStack.top()) {
224 result += QString::fromLatin1("h'" +
225 v.toByteArray().toHex(opts & QCborValue::ExtendedFormat ? ' ' : '\0') +
226 '\'');
227 return;
229 result += QString::fromLatin1("b64'" + v.toByteArray().toBase64() + '\'');
230 return;
231 default:
233 result += QString::fromLatin1("b64'" +
234 v.toByteArray().toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals) +
235 '\'');
236 return;
237 }
239 return appendString(v.toString());
241 return appendArray(v.toArray());
242 case QCborValue::Map:
243 return appendMap(v.toMap());
245 result += "false"_L1;
246 return;
247 case QCborValue::True:
248 result += "true"_L1;
249 return;
250 case QCborValue::Null:
251 result += "null"_L1;
252 return;
254 result += "undefined"_L1;
255 return;
257 result += makeFpString(v.toDouble());
258 return;
260 result += QStringLiteral("<invalid>");
261 return;
262
263 default:
264 // Only tags, extended types, and simple types remain; see below.
265 break;
266 }
267
268 if (v.isTag()) {
269 // We handle all extended types as regular tags, so it won't matter
270 // whether we understand that tag or not.
271 bool byteArrayFormat = opts & QCborValue::ExtendedFormat && isByteArrayEncodingTag(v.tag());
272 if (byteArrayFormat)
273 byteArrayFormatStack.push(int(v.tag()));
274 result += QString::number(quint64(v.tag())) + u'(';
275 appendValue(v.taggedValue());
276 result += u')';
277 if (byteArrayFormat)
278 byteArrayFormatStack.pop();
279 } else {
280 // must be a simple type
281 result += QString::fromLatin1("simple(%1)").arg(quint8(v.toSimpleType()));
282 }
283}
284
311QString QCborValue::toDiagnosticNotation(DiagnosticNotationOptions opts) const
312{
313 return DiagnosticNotation::create(*this, opts);
314}
315
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore\reentrant
Definition qcborarray.h:20
\inmodule QtCore\reentrant
Definition qcbormap.h:21
\inmodule QtCore\reentrant
Definition qcborvalue.h:47
QString toDiagnosticNotation(DiagnosticNotationOptions opts=Compact) const
Creates the diagnostic notation equivalent of this CBOR object and returns it.
\inmodule QtCore
@ FloatingPointShortest
Definition qlocale.h:890
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6340
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
const char * toHex(ushort u, char *buffer)
Definition qpdf.cpp:710
Combined button and popup list for selecting options.
constexpr char toHexUpper(char32_t value) noexcept
Definition qtools_p.h:27
void toByteArray(QByteArray &)
Definition qctf_p.h:76
QCborTag
Definition qcborcommon.h:30
static QString makeFpString(double d)
static bool isByteArrayEncodingTag(QCborTag tag)
AudioChannelLayoutTag tag
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static ControlElement< T > * ptr(QWidget *widget)
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:112
static Q_DECL_CONST_FUNCTION bool qt_is_inf(double d)
Definition qnumeric_p.h:107
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLuint end
GLenum GLuint GLenum GLsizei const GLchar * buf
GLfloat n
GLdouble s
[6]
Definition qopenglext.h:235
GLuint64EXT * result
[6]
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QStringLiteral(str)
unsigned long long quint64
Definition qtypes.h:61
unsigned short ushort
Definition qtypes.h:33
unsigned char quint8
Definition qtypes.h:46
void appendMap(QCborStreamWriter &writer, const QList< std::pair< int, QString > > &values)
[21]
view create()
\inmodule QtCore \reentrant
Definition qchar.h:18