24 #include <QtCore/QIODevice>
25 #include <QtCore/QDataStream>
26 #include <QtCore/QStringList>
27 #include <QtCore/QVariant>
30 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
39 # define isinf(x) (!finite((x)) && (x)==(x))
43 #ifdef _MSC_VER // using MSVC compiler
47 using namespace QJson;
66 QByteArray
serialize(
const QVariant &v,
bool *ok,
int indentLevel = 0);
70 static QByteArray
join(
const QList<QByteArray>& list,
const QByteArray &sep);
71 static QByteArray
join(
const QList<QByteArray>& list,
char sep);
77 for(
const QByteArray &i :
qAsConst(list) ) {
88 for(
const QByteArray &i :
qAsConst(list) ) {
99 #if TTK_QT_VERSION_CHECK(6,0,0)
100 const int type = v.metaType().id();
102 const int type = v.type();
105 if ( ! v.isValid() ) {
108 else if ( type == QMetaType::QVariantList || type == QMetaType::QStringList )
110 const QVariantList list = v.toList();
111 QList<QByteArray> values;
112 for(
const QVariant &var :
qAsConst(list) )
114 QByteArray serializedValue;
116 serializedValue = serialize( var, ok, indentLevel+1);
125 values << serializedValue;
130 values << serializedValue.trimmed();
136 QByteArray indent = buildIndent(indentLevel);
137 str = indent +
"[\n" + join( values,
",\n" ) +
'\n' + indent +
']';
140 QByteArray indent = buildIndent(indentLevel);
141 str = indent +
"[\n" + join( values,
",\n" ) +
'\n' + indent +
']';
144 str =
'[' + join( values,
"," ) +
']';
147 str =
"[ " + join( values,
", " ) +
" ]";
150 else if ( type == QMetaType::QVariantMap )
152 const QVariantMap vmap = v.toMap();
155 QByteArray indent = buildIndent(indentLevel);
159 QByteArray indent = buildIndent(indentLevel);
160 QByteArray nextindent = buildIndent(indentLevel + 1);
161 str = indent +
"{\n" + nextindent;
170 QList<QByteArray> pairs;
171 for (QVariantMap::const_iterator it = vmap.begin(), end = vmap.end(); it != end; ++it) {
173 QByteArray serializedValue = serialize( it.value(), ok, indentLevel);
178 QByteArray
key = escapeString( it.key() );
179 QByteArray value = serializedValue.trimmed();
181 pairs << key +
':' + value;
183 pairs << key +
" : " + value;
188 QByteArray indent = buildIndent(indentLevel + 1);
189 str += join( pairs,
",\n" + indent);
192 str += join( pairs,
',' );
195 str += join( pairs,
", " );
199 QByteArray indent = buildIndent(indentLevel);
200 str +=
'\n' + indent +
'}';
209 else if ( type == QMetaType::QVariantHash )
211 const QVariantHash vhash = v.toHash();
214 QByteArray indent = buildIndent(indentLevel);
218 QByteArray indent = buildIndent(indentLevel);
219 QByteArray nextindent = buildIndent(indentLevel + 1);
220 str = indent +
"{\n" + nextindent;
229 QList<QByteArray> pairs;
230 for (QVariantHash::const_iterator it = vhash.begin(), end = vhash.end(); it != end; ++it) {
231 QByteArray serializedValue = serialize( it.value(), ok, indentLevel + 1);
236 QByteArray
key = escapeString( it.key() );
237 QByteArray value = serializedValue.trimmed();
239 pairs << key +
':' + value;
241 pairs << key +
" : " + value;
246 QByteArray indent = buildIndent(indentLevel + 1);
247 str += join( pairs,
",\n" + indent);
250 str += join( pairs,
',' );
253 str += join( pairs,
", " );
257 QByteArray indent = buildIndent(indentLevel);
258 str +=
'\n' + indent +
'}';
273 str += buildIndent(indentLevel);
281 if ( type == QMetaType::QString || type == QMetaType::QByteArray )
283 str += escapeString( v.toString() );
285 else if ( type == QMetaType::Double || type == QMetaType::Float )
287 const double value = v.toDouble();
294 const bool special = std::isnan(value) || std::isinf(value);
297 if (specialNumbersAllowed) {
298 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
300 if (std::isnan(value)) {
301 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
304 if (std::isnan(value)) {
314 errorMessage += QLatin1String(
"Attempt to write NaN or infinity, which is not supported by json\n");
318 str = QByteArray::number( value ,
'g', doublePrecision);
319 if( !str.contains(
'.' ) && !str.contains(
'e' ) ) {
324 else if ( type == QMetaType::Bool )
326 str += ( v.toBool() ?
"true" :
"false" );
328 else if ( type == QMetaType::ULongLong )
330 str += QByteArray::number( v.value<qulonglong>() );
332 else if ( type == QMetaType::UInt )
334 str += QByteArray::number( v.value<quint32>() );
335 }
else if ( v.canConvert<qlonglong>() ) {
336 str += QByteArray::number( v.value<qlonglong>() );
337 }
else if ( v.canConvert<
int>() ) {
338 str += QByteArray::number( v.value<
int>() );
339 }
else if ( v.canConvert<QString>() ){
341 str += escapeString( v.toString() );
345 errorMessage += QLatin1String(
"Cannot serialize ");
346 errorMessage += v.toString();
347 errorMessage += QLatin1String(
" because type ");
348 errorMessage += QLatin1String(v.typeName());
349 errorMessage += QLatin1String(
" is not supported by QJson\n");
366 for (
int i = 0; i < spaces; i++ ) {
375 result.reserve(str.size() + 2);
377 for (QString::const_iterator it = str.begin(), end = str.end(); it != end; ++it) {
378 ushort unicode = it->unicode();
381 result.append(
"\\\"");
384 result.append(
"\\\\");
387 result.append(
"\\b");
390 result.append(
"\\f");
393 result.append(
"\\n");
396 result.append(
"\\r");
399 result.append(
"\\t");
402 if ( unicode > 0x1F && unicode < 128 ) {
406 qsnprintf(escaped,
sizeof(escaped)/
sizeof(
char),
"\\u%04x", unicode);
407 result.append(escaped);
415 Serializer::Serializer()
420 void Serializer::serialize(
const QVariant &v, QIODevice* io,
bool* ok)
428 if (!io->open(QIODevice::WriteOnly)) {
429 d->errorMessage = QLatin1String(
"Error opening device");
435 if (!io->isWritable()) {
436 d->errorMessage = QLatin1String(
"Device is not readable");
442 const QByteArray str = serialize( v, ok);
443 if (*ok && (io->write(str) != str.length())) {
445 d->errorMessage = QLatin1String(
"Something went wrong while writing to IO device");
449 QByteArray Serializer::serialize(
const QVariant &v,
bool *ok)
453 d->errorMessage.clear();
461 return d->serialize(v, ok);
467 d->specialNumbersAllowed = allow;
473 return d->specialNumbersAllowed;
479 d->indentMode =
mode;
485 d->doublePrecision = precision;
491 return d->indentMode;
497 return d->errorMessage;
bool specialNumbersAllowed() const
Is Nan and/or Infinity allowed?
#define TTKStaticCast(x, y)
static QByteArray buildIndent(int spaces)
bool specialNumbersAllowed
static constexpr wchar_t key[]
IndentMode indentMode() const
Returns one of the indentation modes defined in QJson::IndentMode.
Main class used to convert QVariant objects to JSON data.
IndentMode
How the indentation should work.
void setIndentMode(IndentMode mode=QJson::IndentNone)
set output indentation mode as defined in QJson::IndentMode
QByteArray serialize(const QVariant &v, bool *ok, int indentLevel=0)
static QByteArray join(const QList< QByteArray > &list, const QByteArray &sep)
void setDoublePrecision(int precision)
set double precision used while converting Double
void allowSpecialNumbers(bool allow)
Allow or disallow writing of NaN and/or Infinity (as an extension to QJson)
static QByteArray escapeString(const QString &str)
QString errorMessage() const
Returns the error message.
#define TTK_INIT_PRIVATE(Class)
The class of the ttk private base.
Main class used to convert QVariant objects to JSON data private.