22 #include "serializer.h"
24 #include <QtCore/QDataStream>
25 #include <QtCore/QStringList>
26 #include <QtCore/QVariant>
30 #ifdef _MSC_VER // using MSVC compiler
34 using namespace QJson;
36 class Serializer::SerializerPrivate {
48 QByteArray buildIndent(
int spaces);
49 QByteArray
serialize(
const QVariant &v,
bool *ok,
int indentLevel = 0);
50 QString sanitizeString( QString str );
51 QByteArray join(
const QList<QByteArray>& list,
const QByteArray& sep );
54 QByteArray Serializer::SerializerPrivate::join(
const QList<QByteArray>& list,
const QByteArray& sep ) {
56 Q_FOREACH(
const QByteArray& i, list ) {
70 if ( ! v.isValid() ) {
72 }
else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){
73 const QVariantList list = v.toList();
74 QList<QByteArray> values;
75 Q_FOREACH(
const QVariant& var, list )
78 QByteArray serializedValue = serialize( var, ok, indentLevel);
83 values << serializedValue;
86 if (indentMode == QJson::IndentMinimum) {
87 QByteArray indent = buildIndent(indentLevel - 1);
88 str =
"[\n" + join( values,
",\n" ) +
"\n" + indent +
"]";
90 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
91 QByteArray indent = buildIndent(indentLevel);
92 str =
"[\n" + join( values,
",\n" ) +
"\n" + indent +
"]";
94 else if (indentMode == QJson::IndentCompact) {
95 str =
"[" + join( values,
"," ) +
"]";
98 str =
"[ " + join( values,
", " ) +
" ]";
101 }
else if ( v.type() == QVariant::Map ) {
102 const QVariantMap vmap = v.toMap();
103 QMapIterator<QString, QVariant> it( vmap );
105 if (indentMode == QJson::IndentMinimum) {
106 QByteArray indent = buildIndent(indentLevel);
109 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
110 QByteArray indent = buildIndent(indentLevel);
111 QByteArray nextindent = buildIndent(indentLevel + 1);
112 str = indent +
"{\n" + nextindent;
114 else if (indentMode == QJson::IndentCompact) {
121 QList<QByteArray> pairs;
122 while ( it.hasNext() ) {
125 QByteArray serializedValue = serialize( it.value(), ok, indentLevel);
130 QByteArray key = sanitizeString( it.key() ).toUtf8();
131 QByteArray value = serializedValue;
132 if (indentMode == QJson::IndentCompact) {
133 pairs << key +
":" + value;
135 pairs << key +
" : " + value;
139 if (indentMode == QJson::IndentFull) {
140 QByteArray indent = buildIndent(indentLevel + 1);
141 str += join( pairs,
",\n" + indent);
143 else if (indentMode == QJson::IndentCompact) {
144 str += join( pairs,
"," );
147 str += join( pairs,
", " );
150 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
151 QByteArray indent = buildIndent(indentLevel);
152 str +=
"\n" + indent +
"}";
154 else if (indentMode == QJson::IndentCompact) {
161 }
else if ( v.type() == QVariant::Hash ) {
162 const QVariantHash vhash = v.toHash();
163 QHashIterator<QString, QVariant> it( vhash );
165 if (indentMode == QJson::IndentMinimum) {
166 QByteArray indent = buildIndent(indentLevel);
169 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
170 QByteArray indent = buildIndent(indentLevel);
171 QByteArray nextindent = buildIndent(indentLevel + 1);
172 str = indent +
"{\n" + nextindent;
174 else if (indentMode == QJson::IndentCompact) {
181 QList<QByteArray> pairs;
182 while ( it.hasNext() ) {
185 QByteArray serializedValue = serialize( it.value(), ok, indentLevel);
190 QByteArray key = sanitizeString( it.key() ).toUtf8();
191 QByteArray value = serializedValue;
192 if (indentMode == QJson::IndentCompact) {
193 pairs << key +
":" + value;
195 pairs << key +
" : " + value;
199 if (indentMode == QJson::IndentFull) {
200 QByteArray indent = buildIndent(indentLevel + 1);
201 str += join( pairs,
",\n" + indent);
203 else if (indentMode == QJson::IndentCompact) {
204 str += join( pairs,
"," );
207 str += join( pairs,
", " );
210 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
211 QByteArray indent = buildIndent(indentLevel);
212 str +=
"\n" + indent +
"}";
214 else if (indentMode == QJson::IndentCompact) {
221 }
else if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) {
222 str = sanitizeString( v.toString() ).toUtf8();
223 }
else if (( v.type() == QVariant::Double) || ((QMetaType::Type)v.type() == QMetaType::Float)) {
224 const double value = v.toDouble();
225 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
226 const bool special = _isnan(value) || !_finite(value);
227 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID)
228 const bool special = isnan(value) || isinf(value);
230 const bool special = std::isnan(value) || std::isinf(value);
233 if (specialNumbersAllowed) {
234 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
236 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID)
239 if (std::isnan(value)) {
249 errorMessage += QLatin1String(
"Attempt to write NaN or infinity, which is not supported by json\n");
253 str = QByteArray::number( value ,
'g', doublePrecision);
254 if( ! str.contains(
"." ) && ! str.contains(
"e" ) ) {
258 }
else if ( v.type() == QVariant::Bool ) {
259 str = ( v.toBool() ?
"true" :
"false" );
260 }
else if ( v.type() == QVariant::ULongLong ) {
261 str = QByteArray::number( v.value<qulonglong>() );
262 }
else if ( v.type() == QVariant::UInt ) {
263 str = QByteArray::number( v.value<quint32>() );
264 }
else if ( v.canConvert<qlonglong>() ) {
265 str = QByteArray::number( v.value<qlonglong>() );
266 }
else if ( v.canConvert<
int>() ) {
267 str = QByteArray::number( v.value<
int>() );
268 }
else if ( v.canConvert<QString>() ){
270 str = sanitizeString( v.toString() ).toUtf8();
274 errorMessage += QLatin1String(
"Cannot serialize ");
275 errorMessage += v.toString();
276 errorMessage += QLatin1String(
" because type ");
277 errorMessage += QLatin1String(v.typeName());
278 errorMessage += QLatin1String(
" is not supported by QJson\n");
288 QByteArray Serializer::SerializerPrivate::buildIndent(
int spaces)
294 for (
int i = 0; i < spaces; i++ ) {
300 QString Serializer::SerializerPrivate::sanitizeString( QString str )
302 str.replace( QLatin1String(
"\\" ), QLatin1String(
"\\\\" ) );
306 const ushort* unicode = str.utf16();
309 while ( unicode[ i ] ) {
310 if ( unicode[ i ] < 128 ) {
311 result.append( QChar( unicode[ i ] ) );
314 QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4,
317 result.append( QLatin1String (
"\\u") ).append( hexCode );
323 str.replace( QLatin1String(
"\"" ), QLatin1String(
"\\\"" ) );
324 str.replace( QLatin1String(
"\b" ), QLatin1String(
"\\b" ) );
325 str.replace( QLatin1String(
"\f" ), QLatin1String(
"\\f" ) );
326 str.replace( QLatin1String(
"\n" ), QLatin1String(
"\\n" ) );
327 str.replace( QLatin1String(
"\r" ), QLatin1String(
"\\r" ) );
328 str.replace( QLatin1String(
"\t" ), QLatin1String(
"\\t" ) );
330 return QString( QLatin1String(
"\"%1\"" ) ).arg( str );
333 Serializer::Serializer()
334 : d( new SerializerPrivate )
338 Serializer::~Serializer() {
348 if (!io->open(QIODevice::WriteOnly)) {
349 d->errorMessage = QLatin1String(
"Error opening device");
355 if (!io->isWritable()) {
356 d->errorMessage = QLatin1String(
"Device is not readable");
362 const QByteArray str =
serialize( v, ok);
363 if (*ok && (io->write(str) != str.count())) {
365 d->errorMessage = QLatin1String(
"Something went wrong while writing to IO device");
379 d->errorMessage.clear();
387 return d->serialize(v, ok);
391 d->specialNumbersAllowed = allow;
395 return d->specialNumbersAllowed;
399 d->indentMode = mode;
403 d->doublePrecision = precision;
407 return d->indentMode;
411 return d->errorMessage;