X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=thirdparty%2Fqjson%2Fserializer.cpp;fp=thirdparty%2Fqjson%2Fserializer.cpp;h=41407c2745940b7580b31b221a34f2d505fc9b47;hb=0094c61568bff9f9dd7bafb711f111698e683831;hp=f012246d43f1cded564751922bdb29253928ff13;hpb=c391265484ecb3baa2a00c80658c99ad65963ec6;p=apitrace diff --git a/thirdparty/qjson/serializer.cpp b/thirdparty/qjson/serializer.cpp index f012246..41407c2 100644 --- a/thirdparty/qjson/serializer.cpp +++ b/thirdparty/qjson/serializer.cpp @@ -4,16 +4,16 @@ * Copyright (C) 2009 Flavio Castelli * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. @@ -25,61 +25,31 @@ #include #include +#include + +#ifdef _MSC_VER // using MSVC compiler +#include +#endif + using namespace QJson; class Serializer::SerializerPrivate { + public: + SerializerPrivate() : + specialNumbersAllowed(false), + indentMode(QJson::IndentNone), + doublePrecision(6) { + } + bool specialNumbersAllowed; + IndentMode indentMode; + int doublePrecision; + QByteArray buildIndent(int spaces); + QByteArray serialize( const QVariant &v, int reserved = 0); + QString sanitizeString( QString str ); + QByteArray join( const QList& list, const QByteArray& sep ); }; -Serializer::Serializer() : d( new SerializerPrivate ) { -} - -Serializer::~Serializer() { - delete d; -} - -void Serializer::serialize( const QVariant& v, QIODevice* io, bool* ok ) -{ - Q_ASSERT( io ); - if (!io->isOpen()) { - if (!io->open(QIODevice::WriteOnly)) { - if ( ok != 0 ) - *ok = false; - qCritical ("Error opening device"); - return; - } - } - - if (!io->isWritable()) { - if (ok != 0) - *ok = false; - qCritical ("Device is not readable"); - io->close(); - return; - } - - const QByteArray str = serialize( v ); - if ( !str.isNull() ) { - QDataStream stream( io ); - stream << str; - } else { - if ( ok ) - *ok = false; - } -} - -static QString sanitizeString( QString str ) -{ - str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) ); - str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) ); - str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) ); - str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) ); - str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) ); - str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) ); - str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) ); - return QString( QLatin1String( "\"%1\"" ) ).arg( str ); -} - -static QByteArray join( const QList& list, const QByteArray& sep ) { +QByteArray Serializer::SerializerPrivate::join( const QList& list, const QByteArray& sep ) { QByteArray res; Q_FOREACH( const QByteArray& i, list ) { if ( !res.isEmpty() ) @@ -89,48 +59,141 @@ static QByteArray join( const QList& list, const QByteArray& sep ) { return res; } -QByteArray Serializer::serialize( const QVariant &v ) +QByteArray Serializer::SerializerPrivate::serialize( const QVariant &v, int reserved ) { QByteArray str; bool error = false; + QByteArray indent; if ( ! v.isValid() ) { // invalid or null? str = "null"; - } else if ( v.type() == QVariant::List ) { // variant is a list? + } else if (( v.type() == QVariant::List ) || ( v.type() == QVariant::StringList )){ // an array or a stringlist? const QVariantList list = v.toList(); QList values; - Q_FOREACH( const QVariant& v, list ) + Q_FOREACH( const QVariant& var, list ) { - QByteArray serializedValue = serialize( v ); + reserved++; + QByteArray serializedValue = serialize( var,reserved ); + reserved--; if ( serializedValue.isNull() ) { error = true; break; } values << serializedValue; } - str = "[ " + join( values, ", " ) + " ]"; + + if (indentMode == QJson::IndentMinimum) { + QByteArray indent = buildIndent(reserved - 1); + str = "[\n" + join( values, ",\n" ) + "\n" + indent + "]"; + } + else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { + QByteArray indent = buildIndent(reserved); + str = "[\n" + join( values, ",\n" ) + "\n" + indent + "]"; + } + else if (indentMode == QJson::IndentCompact) { + str = "[" + join( values, "," ) + "]"; + } + else { + str = "[ " + join( values, ", " ) + " ]"; + } + } else if ( v.type() == QVariant::Map ) { // variant is a map? const QVariantMap vmap = v.toMap(); QMapIterator it( vmap ); - str = "{ "; + + if (indentMode == QJson::IndentMinimum) { + QByteArray indent = buildIndent(reserved); + str = indent + "{ "; + } + else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { + QByteArray indent = buildIndent(reserved); + QByteArray nextindent = buildIndent(reserved + 1); + str = indent + "{\n" + nextindent; + } + else if (indentMode == QJson::IndentCompact) { + str = "{"; + } + else { + str = "{ "; + } + QList pairs; while ( it.hasNext() ) { it.next(); - QByteArray serializedValue = serialize( it.value() ); + reserved++; + QByteArray serializedValue = serialize( it.value() , reserved); + reserved--; if ( serializedValue.isNull() ) { error = true; break; } - pairs << sanitizeString( it.key() ).toUtf8() + " : " + serializedValue; + QByteArray key = sanitizeString( it.key() ).toUtf8(); + QByteArray value = serializedValue; + if (indentMode == QJson::IndentCompact) { + pairs << key + ":" + value; + } else { + pairs << key + " : " + value; + } + } + + if (indentMode == QJson::IndentFull) { + QByteArray indent = buildIndent(reserved + 1); + str += join( pairs, ",\n" + indent); + } + else if (indentMode == QJson::IndentCompact) { + str += join( pairs, "," ); } - str += join( pairs, ", " ); - str += " }"; + else { + str += join( pairs, ", " ); + } + + if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) { + QByteArray indent = buildIndent(reserved); + str += "\n" + indent + "}"; + } + else if (indentMode == QJson::IndentCompact) { + str += "}"; + } + else { + str += " }"; + } + } else if (( v.type() == QVariant::String ) || ( v.type() == QVariant::ByteArray )) { // a string or a byte array? str = sanitizeString( v.toString() ).toUtf8(); - } else if ( v.type() == QVariant::Double ) { // a double? - str = QByteArray::number( v.toDouble() ); - if( ! str.contains( "." ) && ! str.contains( "e" ) ) { - str += ".0"; + } else if (( v.type() == QVariant::Double) || ((QMetaType::Type)v.type() == QMetaType::Float)) { // a double or a float? + const double value = v.toDouble(); +#if defined _WIN32 && !defined(Q_OS_SYMBIAN) + const bool special = _isnan(value) || !_finite(value); +#elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) + const bool special = isnan(value) || isinf(value); +#else + const bool special = std::isnan(value) || std::isinf(value); +#endif + if (special) { + if (specialNumbersAllowed) { +#if defined _WIN32 && !defined(Q_OS_SYMBIAN) + if (_isnan(value)) { +#elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) + if (isnan(value)) { +#else + if (std::isnan(value)) { +#endif + str += "NaN"; + } else { + if (value<0) { + str += '-'; + } + str += "Infinity"; + } + } else { + qCritical("Attempt to write NaN or infinity, which is not supported by json"); + error = true; + } + } else { + str = QByteArray::number( value , 'g', doublePrecision); + if( ! str.contains( "." ) && ! str.contains( "e" ) ) { + str += ".0"; + } } } else if ( v.type() == QVariant::Bool ) { // boolean value? str = ( v.toBool() ? "true" : "false" ); @@ -146,7 +209,114 @@ QByteArray Serializer::serialize( const QVariant &v ) error = true; } if ( !error ) + { return str; + } else return QByteArray(); } + +QByteArray Serializer::SerializerPrivate::buildIndent(int spaces) +{ + QByteArray indent; + if (spaces < 0) { + spaces = 0; + } + for (int i = 0; i < spaces; i++ ) { + indent += " "; + } + return indent; +} + +QString Serializer::SerializerPrivate::sanitizeString( QString str ) +{ + str.replace( QLatin1String( "\\" ), QLatin1String( "\\\\" ) ); + + // escape unicode chars + QString result; + const ushort* unicode = str.utf16(); + unsigned int i = 0; + + while ( unicode[ i ] ) { + if ( unicode[ i ] < 128 ) { + result.append( QChar( unicode[ i ] ) ); + } + else { + QString hexCode = QString::number( unicode[ i ], 16 ).rightJustified( 4, + QLatin1Char('0') ); + + result.append( QLatin1String ("\\u") ).append( hexCode ); + } + ++i; + } + str = result; + + str.replace( QLatin1String( "\"" ), QLatin1String( "\\\"" ) ); + str.replace( QLatin1String( "\b" ), QLatin1String( "\\b" ) ); + str.replace( QLatin1String( "\f" ), QLatin1String( "\\f" ) ); + str.replace( QLatin1String( "\n" ), QLatin1String( "\\n" ) ); + str.replace( QLatin1String( "\r" ), QLatin1String( "\\r" ) ); + str.replace( QLatin1String( "\t" ), QLatin1String( "\\t" ) ); + + return QString( QLatin1String( "\"%1\"" ) ).arg( str ); +} + +Serializer::Serializer() + : d( new SerializerPrivate ) +{ +} + +Serializer::~Serializer() { + delete d; +} + +void Serializer::serialize( const QVariant& v, QIODevice* io, bool* ok) +{ + Q_ASSERT( io ); + if (ok) + *ok = false; + + if (!io->isOpen()) { + if (!io->open(QIODevice::WriteOnly)) { + qCritical ("Error opening device"); + return; + } + } + + if (!io->isWritable()) { + qCritical ("Device is not readable"); + io->close(); + return; + } + + const QByteArray str = serialize( v ); + if (io->write(str) == str.count()) { + if (ok) + *ok = true; + } +} + +QByteArray Serializer::serialize( const QVariant &v) +{ + return d->serialize(v); +} + +void QJson::Serializer::allowSpecialNumbers(bool allow) { + d->specialNumbersAllowed = allow; +} + +bool QJson::Serializer::specialNumbersAllowed() const { + return d->specialNumbersAllowed; +} + +void QJson::Serializer::setIndentMode(IndentMode mode) { + d->indentMode = mode; +} + +void QJson::Serializer::setDoublePrecision(int precision) { + d->doublePrecision = precision; +} + +IndentMode QJson::Serializer::indentMode() const { + return d->indentMode; +}