21 #include "serializer.h" 23 #include <QtCore/QDataStream> 24 #include <QtCore/QStringList> 25 #include <QtCore/QVariant> 28 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS) 37 # define isinf(x) (!finite((x)) && (x)==(x)) 41 #ifdef _MSC_VER // using MSVC compiler 45 using namespace QJson;
47 class Serializer::SerializerPrivate {
60 QByteArray
serialize(
const QVariant &v,
bool *ok,
int indentLevel = 0);
62 static QByteArray buildIndent(
int spaces);
63 static QByteArray escapeString(
const QString& str );
64 static QByteArray join(
const QList<QByteArray>& list,
const QByteArray& sep );
67 QByteArray Serializer::SerializerPrivate::join(
const QList<QByteArray>& list,
const QByteArray& sep ) {
69 Q_FOREACH(
const QByteArray& i, list ) {
77 QByteArray Serializer::SerializerPrivate::serialize(
const QVariant &v,
bool *ok,
int indentLevel)
81 if ( ! v.isValid() ) {
83 }
else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){
84 const QVariantList list = v.toList();
85 QList<QByteArray> values;
86 Q_FOREACH(
const QVariant& var, list )
88 QByteArray serializedValue;
90 serializedValue =
serialize( var, ok, indentLevel+1);
96 case QJson::IndentFull :
97 case QJson::IndentMedium :
98 case QJson::IndentMinimum :
99 values << serializedValue;
101 case QJson::IndentCompact :
102 case QJson::IndentNone :
104 values << serializedValue.trimmed();
110 QByteArray indent = buildIndent(indentLevel);
111 str = indent +
"[\n" + join( values,
",\n" ) +
"\n" + indent +
"]";
113 else if (
indentMode == QJson::IndentMinimum) {
114 QByteArray indent = buildIndent(indentLevel);
115 str = indent +
"[\n" + join( values,
",\n" ) +
"\n" + indent +
"]";
117 else if (
indentMode == QJson::IndentCompact) {
118 str =
"[" + join( values,
"," ) +
"]";
121 str =
"[ " + join( values,
", " ) +
" ]";
124 }
else if ( v.type() == QVariant::Map ) {
125 const QVariantMap vmap = v.toMap();
126 QMapIterator<QString, QVariant> it( vmap );
129 QByteArray indent = buildIndent(indentLevel);
133 QByteArray indent = buildIndent(indentLevel);
134 QByteArray nextindent = buildIndent(indentLevel + 1);
135 str = indent +
"{\n" + nextindent;
137 else if (
indentMode == QJson::IndentCompact) {
144 QList<QByteArray> pairs;
145 while ( it.hasNext() ) {
148 QByteArray serializedValue =
serialize( it.value(), ok, indentLevel);
153 QByteArray key = escapeString( it.key() );
154 QByteArray value = serializedValue.trimmed();
156 pairs << key +
":" + value;
158 pairs << key +
" : " + value;
163 QByteArray indent = buildIndent(indentLevel + 1);
164 str += join( pairs,
",\n" + indent);
166 else if (
indentMode == QJson::IndentCompact) {
167 str += join( pairs,
"," );
170 str += join( pairs,
", " );
174 QByteArray indent = buildIndent(indentLevel);
175 str +=
"\n" + indent +
"}";
177 else if (
indentMode == QJson::IndentCompact) {
184 }
else if ( v.type() == QVariant::Hash ) {
185 const QVariantHash vhash = v.toHash();
186 QHashIterator<QString, QVariant> it( vhash );
189 QByteArray indent = buildIndent(indentLevel);
193 QByteArray indent = buildIndent(indentLevel);
194 QByteArray nextindent = buildIndent(indentLevel + 1);
195 str = indent +
"{\n" + nextindent;
197 else if (
indentMode == QJson::IndentCompact) {
204 QList<QByteArray> pairs;
205 while ( it.hasNext() ) {
208 QByteArray serializedValue =
serialize( it.value(), ok, indentLevel + 1);
213 QByteArray key = escapeString( it.key() );
214 QByteArray value = serializedValue.trimmed();
216 pairs << key +
":" + value;
218 pairs << key +
" : " + value;
223 QByteArray indent = buildIndent(indentLevel + 1);
224 str += join( pairs,
",\n" + indent);
226 else if (
indentMode == QJson::IndentCompact) {
227 str += join( pairs,
"," );
230 str += join( pairs,
", " );
234 QByteArray indent = buildIndent(indentLevel);
235 str +=
"\n" + indent +
"}";
237 else if (
indentMode == QJson::IndentCompact) {
247 case QJson::IndentFull :
248 case QJson::IndentMedium :
249 case QJson::IndentMinimum :
250 str += buildIndent(indentLevel);
252 case QJson::IndentCompact :
253 case QJson::IndentNone :
258 if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) {
259 str += escapeString( v.toString() );
260 }
else if (( v.type() == QVariant::Double) || ((QMetaType::Type)v.type() == QMetaType::Float)) {
261 const double value = v.toDouble();
262 #if defined _WIN32 && !defined(Q_OS_SYMBIAN) 263 const bool special = _isnan(value) || !_finite(value);
264 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS) 265 const bool special = isnan(value) || isinf(value);
267 const bool special = std::isnan(value) || std::isinf(value);
271 #if defined _WIN32 && !defined(Q_OS_SYMBIAN) 273 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS) 276 if (std::isnan(value)) {
286 errorMessage += QLatin1String(
"Attempt to write NaN or infinity, which is not supported by json\n");
290 str = QByteArray::number( value ,
'g', doublePrecision);
291 if( ! str.contains(
"." ) && ! str.contains(
"e" ) ) {
295 }
else if ( v.type() == QVariant::Bool ) {
296 str += ( v.toBool() ?
"true" :
"false" );
297 }
else if ( v.type() == QVariant::ULongLong ) {
298 str += QByteArray::number( v.value<qulonglong>() );
299 }
else if ( v.type() == QVariant::UInt ) {
300 str += QByteArray::number( v.value<quint32>() );
301 }
else if ( v.canConvert<qlonglong>() ) {
302 str += QByteArray::number( v.value<qlonglong>() );
303 }
else if ( v.canConvert<
int>() ) {
304 str += QByteArray::number( v.value<
int>() );
305 }
else if ( v.canConvert<QString>() ){
307 str += escapeString( v.toString() );
315 errorMessage += QLatin1String(
" is not supported by QJson\n");
326 QByteArray Serializer::SerializerPrivate::buildIndent(
int spaces)
332 for (
int i = 0; i < spaces; i++ ) {
338 QByteArray Serializer::SerializerPrivate::escapeString(
const QString& str )
341 result.reserve(str.size() + 2);
343 for (QString::const_iterator it = str.begin(); it != str.end(); it++) {
344 ushort unicode = it->unicode();
347 result.append(
"\\\"");
350 result.append(
"\\\\");
353 result.append(
"\\b");
356 result.append(
"\\f");
359 result.append(
"\\n");
362 result.append(
"\\r");
365 result.append(
"\\t");
368 if ( unicode > 0x1F && unicode < 128 ) {
369 result.append(static_cast<char>(unicode));
372 qsnprintf(escaped,
sizeof(escaped)/
sizeof(
char),
"\\u%04x", unicode);
373 result.append(escaped);
381 Serializer::Serializer()
382 : d( new SerializerPrivate )
386 Serializer::~Serializer() {
396 if (!io->open(QIODevice::WriteOnly)) {
397 d->errorMessage = QLatin1String(
"Error opening device");
403 if (!io->isWritable()) {
404 d->errorMessage = QLatin1String(
"Device is not readable");
410 const QByteArray str = serialize( v, ok);
411 if (*ok && (io->write(str) != str.count())) {
413 d->errorMessage = QLatin1String(
"Something went wrong while writing to IO device");
421 return serialize(v, &ok);
427 d->errorMessage.clear();
435 return d->serialize(v, ok);
439 d->specialNumbersAllowed = allow;
443 return d->specialNumbersAllowed;
447 d->indentMode = mode;
451 d->doublePrecision = precision;
455 return d->indentMode;
459 return d->errorMessage;
void setIndentMode(IndentMode mode=QJson::IndentNone)
void allowSpecialNumbers(bool allow)
IndentMode indentMode() const
void serialize(const QVariant &variant, QIODevice *out, bool *ok)
bool specialNumbersAllowed() const
void setDoublePrecision(int precision)
QString errorMessage() const
IndentMode
How the indentation should work.