00001 /* This file is part of qjson 00002 * 00003 * Copyright (C) 2009 Till Adam <adam@kde.org> 00004 * Copyright (C) 2009 Flavio Castelli <flavio@castelli.name> 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License version 2.1, as published by the Free Software Foundation. 00009 * 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this library; see the file COPYING.LIB. If not, write to 00018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "serializer.h" 00023 00024 #include <QtCore/QDataStream> 00025 #include <QtCore/QStringList> 00026 #include <QtCore/QVariant> 00027 00028 #include <cmath> 00029 00030 #ifdef _MSC_VER // using MSVC compiler 00031 #include <float.h> 00032 #endif 00033 00034 using namespace QJson; 00035 00036 class Serializer::SerializerPrivate { 00037 public: 00038 SerializerPrivate() : 00039 specialNumbersAllowed(false), 00040 indentMode(QJson::IndentNone), 00041 doublePrecision(6) { 00042 errorMessage.clear(); 00043 } 00044 QString errorMessage; 00045 bool specialNumbersAllowed; 00046 IndentMode indentMode; 00047 int doublePrecision; 00048 QByteArray buildIndent(int spaces); 00049 QByteArray serialize( const QVariant &v, bool *ok, int indentLevel = 0); 00050 QString sanitizeString( QString str ); 00051 QByteArray join( const QList<QByteArray>& list, const QByteArray& sep ); 00052 }; 00053 00054 QByteArray Serializer::SerializerPrivate::join( const QList<QByteArray>& list, const QByteArray& sep ) { 00055 QByteArray res; 00056 Q_FOREACH( const QByteArray& i, list ) { 00057 if ( !res.isEmpty() ) 00058 res += sep; 00059 res += i; 00060 } 00061 return res; 00062 } 00063 00064 QByteArray Serializer::SerializerPrivate::serialize( const QVariant &v, bool *ok, int indentLevel) 00065 { 00066 QByteArray str; 00067 bool error = false; 00068 QByteArray indent; 00069 00070 if ( ! v.isValid() ) { // invalid or null? 00071 str = "null"; 00072 } else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){ // an array or a stringlist? 00073 const QVariantList list = v.toList(); 00074 QList<QByteArray> values; 00075 Q_FOREACH( const QVariant& var, list ) 00076 { 00077 indentLevel++; 00078 QByteArray serializedValue = serialize( var, ok, indentLevel); 00079 indentLevel--; 00080 if ( !*ok ) { 00081 break; 00082 } 00083 values << serializedValue; 00084 } 00085 00086 if (indentMode == QJson::IndentMinimum) { 00087 QByteArray indent = buildIndent(indentLevel - 1); 00088 str = "[\n" + join( values, ",\n" ) + "\n" + indent + "]"; 00089 } 00090 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { 00091 QByteArray indent = buildIndent(indentLevel); 00092 str = "[\n" + join( values, ",\n" ) + "\n" + indent + "]"; 00093 } 00094 else if (indentMode == QJson::IndentCompact) { 00095 str = "[" + join( values, "," ) + "]"; 00096 } 00097 else { 00098 str = "[ " + join( values, ", " ) + " ]"; 00099 } 00100 00101 } else if ( v.type() == QVariant::Map ) { // variant is a map? 00102 const QVariantMap vmap = v.toMap(); 00103 QMapIterator<QString, QVariant> it( vmap ); 00104 00105 if (indentMode == QJson::IndentMinimum) { 00106 QByteArray indent = buildIndent(indentLevel); 00107 str = indent + "{ "; 00108 } 00109 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { 00110 QByteArray indent = buildIndent(indentLevel); 00111 QByteArray nextindent = buildIndent(indentLevel + 1); 00112 str = indent + "{\n" + nextindent; 00113 } 00114 else if (indentMode == QJson::IndentCompact) { 00115 str = "{"; 00116 } 00117 else { 00118 str = "{ "; 00119 } 00120 00121 QList<QByteArray> pairs; 00122 while ( it.hasNext() ) { 00123 it.next(); 00124 indentLevel++; 00125 QByteArray serializedValue = serialize( it.value(), ok, indentLevel); 00126 indentLevel--; 00127 if ( !*ok ) { 00128 break; 00129 } 00130 QByteArray key = sanitizeString( it.key() ).toUtf8(); 00131 QByteArray value = serializedValue; 00132 if (indentMode == QJson::IndentCompact) { 00133 pairs << key + ":" + value; 00134 } else { 00135 pairs << key + " : " + value; 00136 } 00137 } 00138 00139 if (indentMode == QJson::IndentFull) { 00140 QByteArray indent = buildIndent(indentLevel + 1); 00141 str += join( pairs, ",\n" + indent); 00142 } 00143 else if (indentMode == QJson::IndentCompact) { 00144 str += join( pairs, "," ); 00145 } 00146 else { 00147 str += join( pairs, ", " ); 00148 } 00149 00150 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { 00151 QByteArray indent = buildIndent(indentLevel); 00152 str += "\n" + indent + "}"; 00153 } 00154 else if (indentMode == QJson::IndentCompact) { 00155 str += "}"; 00156 } 00157 else { 00158 str += " }"; 00159 } 00160 00161 } else if ( v.type() == QVariant::Hash ) { // variant is a hash? 00162 const QVariantHash vhash = v.toHash(); 00163 QHashIterator<QString, QVariant> it( vhash ); 00164 00165 if (indentMode == QJson::IndentMinimum) { 00166 QByteArray indent = buildIndent(indentLevel); 00167 str = indent + "{ "; 00168 } 00169 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { 00170 QByteArray indent = buildIndent(indentLevel); 00171 QByteArray nextindent = buildIndent(indentLevel + 1); 00172 str = indent + "{\n" + nextindent; 00173 } 00174 else if (indentMode == QJson::IndentCompact) { 00175 str = "{"; 00176 } 00177 else { 00178 str = "{ "; 00179 } 00180 00181 QList<QByteArray> pairs; 00182 while ( it.hasNext() ) { 00183 it.next(); 00184 indentLevel++; 00185 QByteArray serializedValue = serialize( it.value(), ok, indentLevel); 00186 indentLevel--; 00187 if ( !*ok ) { 00188 break; 00189 } 00190 QByteArray key = sanitizeString( it.key() ).toUtf8(); 00191 QByteArray value = serializedValue; 00192 if (indentMode == QJson::IndentCompact) { 00193 pairs << key + ":" + value; 00194 } else { 00195 pairs << key + " : " + value; 00196 } 00197 } 00198 00199 if (indentMode == QJson::IndentFull) { 00200 QByteArray indent = buildIndent(indentLevel + 1); 00201 str += join( pairs, ",\n" + indent); 00202 } 00203 else if (indentMode == QJson::IndentCompact) { 00204 str += join( pairs, "," ); 00205 } 00206 else { 00207 str += join( pairs, ", " ); 00208 } 00209 00210 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { 00211 QByteArray indent = buildIndent(indentLevel); 00212 str += "\n" + indent + "}"; 00213 } 00214 else if (indentMode == QJson::IndentCompact) { 00215 str += "}"; 00216 } 00217 else { 00218 str += " }"; 00219 } 00220 00221 } else if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) { // a string or a byte array? 00222 str = sanitizeString( v.toString() ).toUtf8(); 00223 } else if (( v.type() == QVariant::Double) || ((QMetaType::Type)v.type() == QMetaType::Float)) { // a double or a float? 00224 const double value = v.toDouble(); 00225 #if defined _WIN32 && !defined(Q_OS_SYMBIAN) 00226 const bool special = _isnan(value) || !_finite(value); 00227 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) 00228 const bool special = isnan(value) || isinf(value); 00229 #else 00230 const bool special = std::isnan(value) || std::isinf(value); 00231 #endif 00232 if (special) { 00233 if (specialNumbersAllowed) { 00234 #if defined _WIN32 && !defined(Q_OS_SYMBIAN) 00235 if (_isnan(value)) { 00236 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) 00237 if (isnan(value)) { 00238 #else 00239 if (std::isnan(value)) { 00240 #endif 00241 str += "NaN"; 00242 } else { 00243 if (value<0) { 00244 str += '-'; 00245 } 00246 str += "Infinity"; 00247 } 00248 } else { 00249 errorMessage += QLatin1String("Attempt to write NaN or infinity, which is not supported by json\n"); 00250 *ok = false; 00251 } 00252 } else { 00253 str = QByteArray::number( value , 'g', doublePrecision); 00254 if( ! str.contains( "." ) && ! str.contains( "e" ) ) { 00255 str += ".0"; 00256 } 00257 } 00258 } else if ( v.type() == QVariant::Bool ) { // boolean value? 00259 str = ( v.toBool() ? "true" : "false" ); 00260 } else if ( v.type() == QVariant::ULongLong ) { // large unsigned number? 00261 str = QByteArray::number( v.value<qulonglong>() ); 00262 } else if ( v.type() == QVariant::UInt ) { // unsigned int number? 00263 str = QByteArray::number( v.value<quint32>() ); 00264 } else if ( v.canConvert<qlonglong>() ) { // any signed number? 00265 str = QByteArray::number( v.value<qlonglong>() ); 00266 } else if ( v.canConvert<int>() ) { // unsigned short number? 00267 str = QByteArray::number( v.value<int>() ); 00268 } else if ( v.canConvert<QString>() ){ // can value be converted to string? 00269 // this will catch QDate, QDateTime, QUrl, ... 00270 str = sanitizeString( v.toString() ).toUtf8(); 00271 //TODO: catch other values like QImage, QRect, ... 00272 } else { 00273 *ok = false; 00274 errorMessage += QLatin1String("Cannot serialize "); 00275 errorMessage += v.toString(); 00276 errorMessage += QLatin1String(" because type "); 00277 errorMessage += QLatin1String(v.typeName()); 00278 errorMessage += QLatin1String(" is not supported by QJson\n"); 00279 } 00280 if ( *ok ) 00281 { 00282 return str; 00283 } 00284 else 00285 return QByteArray(); 00286 } 00287 00288 QByteArray Serializer::SerializerPrivate::buildIndent(int spaces) 00289 { 00290 QByteArray indent; 00291 if (spaces < 0) { 00292 spaces = 0; 00293 } 00294 for (int i = 0; i < spaces; i++ ) { 00295 indent += " "; 00296 } 00297 return indent; 00298 } 00299 00300 QString Serializer::SerializerPrivate::sanitizeString( QString str ) 00301 { 00302 str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) ); 00303 00304 // escape unicode chars 00305 QString result; 00306 const ushort* unicode = str.utf16(); 00307 unsigned int i = 0; 00308 00309 while ( unicode[ i ] ) { 00310 if ( unicode[ i ] < 128 ) { 00311 result.append( QChar( unicode[ i ] ) ); 00312 } 00313 else { 00314 QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4, 00315 QLatin1Char('0') ); 00316 00317 result.append( QLatin1String ("\\u") ).append( hexCode ); 00318 } 00319 ++i; 00320 } 00321 str = result; 00322 00323 str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) ); 00324 str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) ); 00325 str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) ); 00326 str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) ); 00327 str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) ); 00328 str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) ); 00329 00330 return QString( QLatin1String( "\"%1\"" ) ).arg( str ); 00331 } 00332 00333 Serializer::Serializer() 00334 : d( new SerializerPrivate ) 00335 { 00336 } 00337 00338 Serializer::~Serializer() { 00339 delete d; 00340 } 00341 00342 void Serializer::serialize( const QVariant& v, QIODevice* io, bool* ok) 00343 { 00344 Q_ASSERT( io ); 00345 *ok = true; 00346 00347 if (!io->isOpen()) { 00348 if (!io->open(QIODevice::WriteOnly)) { 00349 d->errorMessage = QLatin1String("Error opening device"); 00350 *ok = false; 00351 return; 00352 } 00353 } 00354 00355 if (!io->isWritable()) { 00356 d->errorMessage = QLatin1String("Device is not readable"); 00357 io->close(); 00358 *ok = false; 00359 return; 00360 } 00361 00362 const QByteArray str = serialize( v, ok); 00363 if (*ok && (io->write(str) != str.count())) { 00364 *ok = false; 00365 d->errorMessage = QLatin1String("Something went wrong while writing to IO device"); 00366 } 00367 } 00368 00369 QByteArray Serializer::serialize( const QVariant &v) 00370 { 00371 bool ok; 00372 00373 return serialize(v, &ok); 00374 } 00375 00376 QByteArray Serializer::serialize( const QVariant &v, bool *ok) 00377 { 00378 bool _ok = true; 00379 d->errorMessage.clear(); 00380 00381 if (ok) { 00382 *ok = true; 00383 } else { 00384 ok = &_ok; 00385 } 00386 00387 return d->serialize(v, ok); 00388 } 00389 00390 void QJson::Serializer::allowSpecialNumbers(bool allow) { 00391 d->specialNumbersAllowed = allow; 00392 } 00393 00394 bool QJson::Serializer::specialNumbersAllowed() const { 00395 return d->specialNumbersAllowed; 00396 } 00397 00398 void QJson::Serializer::setIndentMode(IndentMode mode) { 00399 d->indentMode = mode; 00400 } 00401 00402 void QJson::Serializer::setDoublePrecision(int precision) { 00403 d->doublePrecision = precision; 00404 } 00405 00406 IndentMode QJson::Serializer::indentMode() const { 00407 return d->indentMode; 00408 } 00409 00410 QString QJson::Serializer::errorMessage() const { 00411 return d->errorMessage; 00412 } 00413
|
hosts this site. |
Send comments to: QJson Developers |