1 /* This file is part of qjson
3 * Copyright (C) 2009 Till Adam <adam@kde.org>
4 * Copyright (C) 2009 Flavio Castelli <flavio@castelli.name>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
22 #include "serializer.h"
24 #include <QtCore/QDataStream>
25 #include <QtCore/QStringList>
26 #include <QtCore/QVariant>
30 using namespace QJson;
32 class Serializer::SerializerPrivate {
34 SerializerPrivate() : specialNumbersAllowed(false) {}
35 bool specialNumbersAllowed;
36 QString sanitizeString( QString str );
39 QString Serializer::SerializerPrivate::sanitizeString( QString str )
41 str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) );
43 // escape unicode chars
45 const ushort* unicode = str.utf16();
48 while ( unicode[ i ] ) {
49 if ( unicode[ i ] < 128 ) {
50 result.append( QChar( unicode[ i ] ) );
53 QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4,
56 result.append( QLatin1String ("\\u") ).append( hexCode );
62 str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) );
63 str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) );
64 str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) );
65 str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) );
66 str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) );
67 str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) );
69 return QString( QLatin1String( "\"%1\"" ) ).arg( str );
72 Serializer::Serializer()
73 : d( new SerializerPrivate )
77 Serializer::~Serializer() {
81 void Serializer::serialize( const QVariant& v, QIODevice* io, bool* ok )
85 if (!io->open(QIODevice::WriteOnly)) {
88 qCritical ("Error opening device");
93 if (!io->isWritable()) {
96 qCritical ("Device is not readable");
101 const QByteArray str = serialize( v );
102 if ( !str.isNull() ) {
103 QDataStream stream( io );
111 static QByteArray join( const QList<QByteArray>& list, const QByteArray& sep ) {
113 Q_FOREACH( const QByteArray& i, list ) {
114 if ( !res.isEmpty() )
121 QByteArray Serializer::serialize( const QVariant &v )
126 if ( ! v.isValid() ) { // invalid or null?
128 } else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){ // an array or a stringlist?
129 const QVariantList list = v.toList();
130 QList<QByteArray> values;
131 Q_FOREACH( const QVariant& v, list )
133 QByteArray serializedValue = serialize( v );
134 if ( serializedValue.isNull() ) {
138 values << serializedValue;
140 str = "[ " + join( values, ", " ) + " ]";
141 } else if ( v.type() == QVariant::Map ) { // variant is a map?
142 const QVariantMap vmap = v.toMap();
143 QMapIterator<QString, QVariant> it( vmap );
145 QList<QByteArray> pairs;
146 while ( it.hasNext() ) {
148 QByteArray serializedValue = serialize( it.value() );
149 if ( serializedValue.isNull() ) {
153 pairs << d->sanitizeString( it.key() ).toUtf8() + " : " + serializedValue;
155 str += join( pairs, ", " );
157 } else if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) { // a string or a byte array?
158 str = d->sanitizeString( v.toString() ).toUtf8();
159 } else if (( v.type() == QVariant::Double) || (v.type() == QMetaType::Float)) { // a double or a float?
160 const double value = v.toDouble();
161 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
162 const bool special = _isnan(value) || !_finite(value);
163 #elif defined(Q_OS_SYMBIAN)
164 const bool special = isnan(value) || isinf(value);
166 const bool special = std::isnan(value) || std::isinf(value);
169 if (specialNumbersAllowed()) {
170 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
172 #elif defined(Q_OS_SYMBIAN)
175 if (std::isnan(value)) {
185 qCritical("Attempt to write NaN or infinity, which is not supported by json");
189 str = QByteArray::number( value );
190 if( ! str.contains( "." ) && ! str.contains( "e" ) ) {
194 } else if ( v.type() == QVariant::Bool ) { // boolean value?
195 str = ( v.toBool() ? "true" : "false" );
196 } else if ( v.type() == QVariant::ULongLong ) { // large unsigned number?
197 str = QByteArray::number( v.value<qulonglong>() );
198 } else if ( v.canConvert<qlonglong>() ) { // any signed number?
199 str = QByteArray::number( v.value<qlonglong>() );
200 } else if ( v.canConvert<QString>() ){ // can value be converted to string?
201 // this will catch QDate, QDateTime, QUrl, ...
202 str = d->sanitizeString( v.toString() ).toUtf8();
203 //TODO: catch other values like QImage, QRect, ...
213 void QJson::Serializer::allowSpecialNumbers(bool allow) {
214 d->specialNumbersAllowed = allow;
217 bool QJson::Serializer::specialNumbersAllowed() const {
218 return d->specialNumbersAllowed;