2
* Copyright (C) 2008 Fabien Chereau
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
#include "StelJsonParser.hpp"
23
void skipJson(QIODevice& input)
25
// There is a weakness in this code -- it will cause any standalone '/' to be absorbed.
27
while (input.getChar(&c))
29
if (QChar(c).isSpace() || c=='\n')
41
if (!input.getChar(&c))
50
// We have a problem, we removed an '/'..
51
qWarning() << "I removed a '/' while parsing JSON file.";
59
bool tryReadChar(QIODevice& input, char c)
62
if (!input.getChar(&r))
72
QString readString(QIODevice& input)
78
throw std::runtime_error("Expected '\"' at beginning of string");
89
if (c=='f') c='\f'; break;
90
if (c=='n') c='\n'; break;
91
if (c=='r') c='\r'; break;
92
if (c=='t') c='\t'; break;
93
if (c=='u') qWarning() << "don't support \\uxxxx char"; break;
99
throw std::runtime_error(qPrintable(QString("End of file before end of string: "+name)));
105
QVariant readOther(QIODevice& input)
109
while (input.getChar(&c))
111
if (QChar(c).isSpace() || c==']' || c=='}' || c==',')
118
QTextStream ts(&str);
122
return QVariant(true);
124
return QVariant(false);
129
int i = v.toInt(&ok);
131
double d = v.toDouble(&ok);
137
// Parse the given input stream
138
QVariant StelJsonParser::parse(QIODevice& input) const
142
if (tryReadChar(input, '{'))
144
// We've got an object (a tuple)
147
if (tryReadChar(input, '}'))
152
QString key = readString(input);
154
if (!tryReadChar(input, ':'))
155
throw std::runtime_error(qPrintable(QString("Expected ':' after a member name: ")+key));
158
map.insert(key, parse(input));
161
if (!tryReadChar(input, ','))
167
if (!tryReadChar(input, '}'))
168
throw std::runtime_error("Expected '}' to close an object");
171
else if (tryReadChar(input, '['))
173
// We've got an array (a vector)
176
if (tryReadChar(input, ']'))
181
list.append(parse(input));
183
if (!tryReadChar(input, ','))
189
if (!tryReadChar(input, ']'))
190
throw std::runtime_error("Expected ']' to close an array");
194
else if (tryReadChar(input, '\"'))
196
// We've got a string
197
input.ungetChar('\"');
198
return readString(input);
200
return readOther(input);
203
// Serialize the passed QVariant as JSON into the output QIODevice
204
void StelJsonParser::write(const QVariant& v, QIODevice& output, int indentLevel) const
209
output.write(v.toBool()==true ? "true" : "false");
211
case QVariant::Invalid:
212
output.write("null");
214
case QVariant::String:
216
QString s(v.toString());
217
s.replace('\"', "\\\"");
218
//s.replace('\\', "\\\\");
219
//s.replace('/', "\\/");
220
s.replace('\b', "\\b");
221
s.replace('\n', "\\n");
222
s.replace('\f', "\\f");
223
s.replace('\r', "\\r");
224
s.replace('\t', "\\t");
225
output.write(QString("\"%1\"").arg(s).toUtf8());
229
case QVariant::Double:
230
output.write(v.toString().toUtf8());
235
const QVariantList& l = v.toList();
236
for (int i=0;i<l.size();++i)
238
// Break line if we start an JSON Object for nice looking
239
if (l.at(i).type()==QVariant::Map)
240
output.putChar('\n');
241
write(l.at(i), output, indentLevel);
250
const QByteArray prepend(indentLevel, '\t');
251
output.write(prepend);
254
const QVariantMap& m = v.toMap();
256
for (QVariantMap::ConstIterator i=m.begin();i!=m.end();++i)
258
output.write(prepend);
259
output.write("\t\"");
260
output.write(i.key().toUtf8());
261
output.write("\": ");
262
// Break line if we start an JSON Object for nice looking
263
if (i.value().type()==QVariant::Map)
264
output.putChar('\n');
265
write(i.value(), output, indentLevel);
268
output.putChar('\n');
270
output.write(prepend);
276
qWarning() << "Cannot serialize QVariant of type " << v.typeName() << " in JSON";