22 #include "serializer.h"
24 #include <QtCore/QDataStream>
25 #include <QtCore/QStringList>
26 #include <QtCore/QVariant>
29 #if defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
38 # define isinf(x) (!finite((x)) && (x)==(x))
42 #ifdef _MSC_VER // using MSVC compiler
46 using namespace QJson;
48 class Serializer::SerializerPrivate {
61 QByteArray
serialize(
const QVariant &v,
bool *ok,
int indentLevel = 0);
63 static QByteArray buildIndent(
int spaces);
64 static QByteArray escapeString(
const QString& str );
65 static QByteArray join(
const QList<QByteArray>& list,
const QByteArray& sep );
66 static QByteArray join(
const QList<QByteArray>& list,
char sep );
69 QByteArray Serializer::SerializerPrivate::join(
const QList<QByteArray>& list,
const QByteArray& sep ) {
71 Q_FOREACH(
const QByteArray& i, list ) {
79 QByteArray Serializer::SerializerPrivate::join(
const QList<QByteArray>& list,
char sep ) {
81 Q_FOREACH(
const QByteArray& i, list ) {
89 QByteArray Serializer::SerializerPrivate::serialize(
const QVariant &v,
bool *ok,
int indentLevel)
92 const QVariant::Type type = v.type();
94 if ( ! v.isValid() ) {
96 }
else if (( type == QVariant::List ) || ( type == QVariant::StringList )) {
97 const QVariantList list = v.toList();
98 QList<QByteArray> values;
99 Q_FOREACH(
const QVariant& var, list )
101 QByteArray serializedValue;
103 serializedValue = serialize( var, ok, indentLevel+1);
109 case QJson::IndentFull :
110 case QJson::IndentMedium :
111 case QJson::IndentMinimum :
112 values << serializedValue;
114 case QJson::IndentCompact :
115 case QJson::IndentNone :
117 values << serializedValue.trimmed();
122 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull ) {
123 QByteArray indent = buildIndent(indentLevel);
124 str = indent +
"[\n" + join( values,
",\n" ) +
'\n' + indent +
']';
126 else if (indentMode == QJson::IndentMinimum) {
127 QByteArray indent = buildIndent(indentLevel);
128 str = indent +
"[\n" + join( values,
",\n" ) +
'\n' + indent +
']';
130 else if (indentMode == QJson::IndentCompact) {
131 str =
'[' + join( values,
"," ) +
']';
134 str =
"[ " + join( values,
", " ) +
" ]";
137 }
else if ( type == QVariant::Map ) {
138 const QVariantMap vmap = v.toMap();
140 if (indentMode == QJson::IndentMinimum) {
141 QByteArray indent = buildIndent(indentLevel);
144 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
145 QByteArray indent = buildIndent(indentLevel);
146 QByteArray nextindent = buildIndent(indentLevel + 1);
147 str = indent +
"{\n" + nextindent;
149 else if (indentMode == QJson::IndentCompact) {
156 QList<QByteArray> pairs;
157 for (QVariantMap::const_iterator it = vmap.begin(), end = vmap.end(); it != end; ++it) {
159 QByteArray serializedValue = serialize( it.value(), ok, indentLevel);
164 QByteArray key = escapeString( it.key() );
165 QByteArray value = serializedValue.trimmed();
166 if (indentMode == QJson::IndentCompact) {
167 pairs << key +
':' + value;
169 pairs << key +
" : " + value;
173 if (indentMode == QJson::IndentFull) {
174 QByteArray indent = buildIndent(indentLevel + 1);
175 str += join( pairs,
",\n" + indent);
177 else if (indentMode == QJson::IndentCompact) {
178 str += join( pairs,
',' );
181 str += join( pairs,
", " );
184 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
185 QByteArray indent = buildIndent(indentLevel);
186 str +=
'\n' + indent +
'}';
188 else if (indentMode == QJson::IndentCompact) {
195 }
else if ( type == QVariant::Hash ) {
196 const QVariantHash vhash = v.toHash();
198 if (indentMode == QJson::IndentMinimum) {
199 QByteArray indent = buildIndent(indentLevel);
202 else if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
203 QByteArray indent = buildIndent(indentLevel);
204 QByteArray nextindent = buildIndent(indentLevel + 1);
205 str = indent +
"{\n" + nextindent;
207 else if (indentMode == QJson::IndentCompact) {
214 QList<QByteArray> pairs;
215 for (QVariantHash::const_iterator it = vhash.begin(), end = vhash.end(); it != end; ++it) {
216 QByteArray serializedValue = serialize( it.value(), ok, indentLevel + 1);
221 QByteArray key = escapeString( it.key() );
222 QByteArray value = serializedValue.trimmed();
223 if (indentMode == QJson::IndentCompact) {
224 pairs << key +
':' + value;
226 pairs << key +
" : " + value;
230 if (indentMode == QJson::IndentFull) {
231 QByteArray indent = buildIndent(indentLevel + 1);
232 str += join( pairs,
",\n" + indent);
234 else if (indentMode == QJson::IndentCompact) {
235 str += join( pairs,
',' );
238 str += join( pairs,
", " );
241 if (indentMode == QJson::IndentMedium || indentMode == QJson::IndentFull) {
242 QByteArray indent = buildIndent(indentLevel);
243 str +=
'\n' + indent +
'}';
245 else if (indentMode == QJson::IndentCompact) {
255 case QJson::IndentFull :
256 case QJson::IndentMedium :
257 case QJson::IndentMinimum :
258 str += buildIndent(indentLevel);
260 case QJson::IndentCompact :
261 case QJson::IndentNone :
266 if (( type == QVariant::String ) || ( type == QVariant::ByteArray )) {
267 str += escapeString( v.toString() );
268 }
else if (( type == QVariant::Double) || ((QMetaType::Type)type == QMetaType::Float)) {
269 const double value = v.toDouble();
270 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
271 const bool special = _isnan(value) || !_finite(value);
272 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
273 const bool special = isnan(value) || isinf(value);
275 const bool special = std::isnan(value) || std::isinf(value);
278 if (specialNumbersAllowed) {
279 #if defined _WIN32 && !defined(Q_OS_SYMBIAN)
281 #elif defined(Q_OS_SYMBIAN) || defined(Q_OS_ANDROID) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_SOLARIS)
284 if (std::isnan(value)) {
294 errorMessage += QLatin1String(
"Attempt to write NaN or infinity, which is not supported by json\n");
298 str = QByteArray::number( value ,
'g', doublePrecision);
299 if( !str.contains(
'.' ) && !str.contains(
'e' ) ) {
303 }
else if ( type == QVariant::Bool ) {
304 str += ( v.toBool() ?
"true" :
"false" );
305 }
else if ( type == QVariant::ULongLong ) {
306 str += QByteArray::number( v.value<qulonglong>() );
307 }
else if ( type == QVariant::UInt ) {
308 str += QByteArray::number( v.value<quint32>() );
309 }
else if ( v.canConvert<qlonglong>() ) {
310 str += QByteArray::number( v.value<qlonglong>() );
311 }
else if ( v.canConvert<
int>() ) {
312 str += QByteArray::number( v.value<
int>() );
313 }
else if ( v.canConvert<QString>() ){
315 str += escapeString( v.toString() );
319 errorMessage += QLatin1String(
"Cannot serialize ");
320 errorMessage += v.toString();
321 errorMessage += QLatin1String(
" because type ");
322 errorMessage += QLatin1String(v.typeName());
323 errorMessage += QLatin1String(
" is not supported by QJson\n");
334 QByteArray Serializer::SerializerPrivate::buildIndent(
int spaces)
340 for (
int i = 0; i < spaces; i++ ) {
346 QByteArray Serializer::SerializerPrivate::escapeString(
const QString& str )
349 result.reserve(str.size() + 2);
351 for (QString::const_iterator it = str.begin(), end = str.end(); it != end; ++it) {
352 ushort unicode = it->unicode();
355 result.append(
"\\\"");
358 result.append(
"\\\\");
361 result.append(
"\\b");
364 result.append(
"\\f");
367 result.append(
"\\n");
370 result.append(
"\\r");
373 result.append(
"\\t");
376 if ( unicode > 0x1F && unicode < 128 ) {
377 result.append(
static_cast<char>(unicode));
380 qsnprintf(escaped,
sizeof(escaped)/
sizeof(
char),
"\\u%04x", unicode);
381 result.append(escaped);
389 Serializer::Serializer()
390 : d( new SerializerPrivate )
394 Serializer::~Serializer() {
404 if (!io->open(QIODevice::WriteOnly)) {
405 d->errorMessage = QLatin1String(
"Error opening device");
411 if (!io->isWritable()) {
412 d->errorMessage = QLatin1String(
"Device is not readable");
418 const QByteArray str =
serialize( v, ok);
419 if (*ok && (io->write(str) != str.count())) {
421 d->errorMessage = QLatin1String(
"Something went wrong while writing to IO device");
435 d->errorMessage.clear();
443 return d->serialize(v, ok);
447 d->specialNumbersAllowed = allow;
451 return d->specialNumbersAllowed;
455 d->indentMode = mode;
459 d->doublePrecision = precision;
463 return d->indentMode;
467 return d->errorMessage;