Skip to content

Commit d344f39

Browse files
committed
Use Niels Lohmann's JSON library everywhere
We started to use Niels Lohmann's JSON library instead of the one included in Qt for the Export JSON dialog a while ago because Qt's implementation showed some problems. To avoid any similar issues and because Niels' library has a much nicer API, this commit migrates all our code to his library.
1 parent b803e3c commit d344f39

File tree

7 files changed

+100
-100
lines changed

7 files changed

+100
-100
lines changed

src/EditDialog.cpp

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <QImageReader>
1414
#include <QBuffer>
1515
#include <QModelIndex>
16-
#include <QJsonDocument>
1716
#include <QtXml/QDomDocument>
1817
#include <QMessageBox>
1918
#include <QPrinter>
@@ -23,6 +22,9 @@
2322
#include <QTextDocument>
2423

2524
#include <Qsci/qsciscintilla.h>
25+
#include <json.hpp>
26+
27+
using json = nlohmann::json;
2628

2729
EditDialog::EditDialog(QWidget* parent)
2830
: QDialog(parent),
@@ -479,29 +481,33 @@ void EditDialog::accept()
479481
}
480482
case DockTextEdit::JSON:
481483
{
484+
sciEdit->clearErrorIndicators();
485+
482486
QString oldData = currentIndex.data(Qt::EditRole).toString();
483487

484488
QString newData;
485-
QJsonParseError parseError;
486-
QJsonDocument jsonDoc = QJsonDocument::fromJson(sciEdit->text().toUtf8(), &parseError);
487-
bool proceed;
489+
bool proceed = true;
490+
json jsonDoc;
488491

489-
sciEdit->clearErrorIndicators();
490-
if (parseError.error != QJsonParseError::NoError)
491-
sciEdit->setErrorIndicator(parseError.offset-1);
492+
try {
493+
jsonDoc = json::parse(sciEdit->text().toStdString());
494+
} catch(json::parse_error& parseError) {
495+
sciEdit->setErrorIndicator(static_cast<int>(parseError.byte - 1));
492496

493-
if (!jsonDoc.isNull()) {
497+
proceed = promptInvalidData("JSON", parseError.what());
498+
}
499+
500+
if (!jsonDoc.is_null()) {
494501
if (mustIndentAndCompact)
495502
// Compact the JSON data before storing
496-
newData = QString(jsonDoc.toJson(QJsonDocument::Compact));
503+
newData = QString::fromStdString(jsonDoc.dump());
497504
else
498505
newData = sciEdit->text();
499-
proceed = (oldData != newData);
500-
501506
} else {
502507
newData = sciEdit->text();
503-
proceed = (oldData != newData && promptInvalidData("JSON", parseError.errorString()));
504508
}
509+
proceed = proceed && (oldData != newData);
510+
505511
if (proceed)
506512
// The data is different, so commit it back to the database
507513
emit recordTextUpdated(currentIndex, newData.toUtf8(), false);
@@ -577,23 +583,26 @@ void EditDialog::setDataInBuffer(const QByteArray& data, DataSources source)
577583
}
578584
case DockTextEdit::JSON:
579585
{
580-
QJsonParseError parseError;
581-
QJsonDocument jsonDoc = QJsonDocument::fromJson(QByteArray(data.constData(), data.size()), &parseError);
586+
sciEdit->clearErrorIndicators();
587+
588+
json jsonDoc;
582589

583-
if (mustIndentAndCompact && !jsonDoc.isNull()) {
590+
try {
591+
jsonDoc = json::parse(std::string(data.constData(), static_cast<size_t>(data.size())));
592+
} catch(json::parse_error& parseError) {
593+
sciEdit->setErrorIndicator(static_cast<int>(parseError.byte - 1));
594+
}
595+
596+
if (mustIndentAndCompact && !jsonDoc.is_null() && !jsonDoc.is_discarded()) {
584597
// Load indented JSON into the JSON editor
585-
textData = QString(jsonDoc.toJson(QJsonDocument::Indented));
598+
textData = QString::fromStdString(jsonDoc.dump(4));
586599
} else {
587600
// Fallback case. The data is not yet valid JSON or no auto-formatting applied.
588601
textData = QString::fromUtf8(data.constData(), data.size());
589602
}
590-
sciEdit->setText(textData);
591603

592-
sciEdit->clearErrorIndicators();
593-
if (parseError.error != QJsonParseError::NoError)
594-
sciEdit->setErrorIndicator(parseError.offset-1);
604+
sciEdit->setText(textData);
595605
sciEdit->setEnabled(true);
596-
597606
}
598607

599608
break;
@@ -742,8 +751,8 @@ int EditDialog::checkDataType(const QByteArray& data)
742751
{
743752
if (cellData.startsWith("<?xml"))
744753
return XML;
745-
QJsonDocument jsonDoc = QJsonDocument::fromJson(cellData);
746-
if (!jsonDoc.isNull())
754+
755+
if(!json::parse(cellData, nullptr, false).is_discarded())
747756
return JSON;
748757
else
749758
return Text;

src/RemoteDatabase.cpp

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,17 @@
1010
#include <QDir>
1111
#include <QStandardPaths>
1212
#include <QUrlQuery>
13-
#include <QJsonDocument>
14-
#include <QJsonObject>
1513
#include <QtNetwork/QHttpMultiPart>
1614
#include <QTimeZone>
15+
#include <json.hpp>
1716

1817
#include "RemoteDatabase.h"
1918
#include "version.h"
2019
#include "Settings.h"
2120
#include "sqlite.h"
2221

22+
using json = nlohmann::json;
23+
2324
RemoteDatabase::RemoteDatabase() :
2425
m_manager(new QNetworkAccessManager),
2526
m_configurationManager(new QNetworkConfigurationManager),
@@ -149,7 +150,7 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
149150

150151
// Add cloned database to list of local databases
151152
QString saveFileAs = localAdd(reply->url().fileName(), reply->property("certfile").toString(),
152-
reply->url(), QUrlQuery(reply->url()).queryItemValue("commit"));
153+
reply->url(), QUrlQuery(reply->url()).queryItemValue("commit").toStdString());
153154

154155
// Save the downloaded data under the generated file name
155156
QFile file(saveFileAs);
@@ -185,15 +186,14 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
185186
case RequestTypeLicenceList:
186187
{
187188
// Read and check results
188-
QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
189-
if(json.isNull() || !json.isObject())
189+
json obj = json::parse(reply->readAll(), nullptr, false);
190+
if(obj.is_discarded() || !obj.is_object())
190191
break;
191-
QJsonObject obj = json.object();
192192

193193
// Parse data and build licence map (short name -> long name)
194-
QMap<QString, QString> licences;
195-
for(auto it=obj.constBegin();it!=obj.constEnd();++it)
196-
licences.insert(it.key(), it.value().toObject().value("full_name").toString());
194+
QMap<std::string, std::string> licences;
195+
for(auto it=obj.cbegin();it!=obj.cend();++it)
196+
licences.insert(it.key(), it.value()["full_name"]);
197197

198198
// Send licence map to anyone who's interested
199199
emit gotLicenceList(licences);
@@ -202,27 +202,18 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
202202
case RequestTypeBranchList:
203203
{
204204
// Read and check results
205-
QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
206-
if(json.isNull() || !json.isObject())
205+
json obj = json::parse(reply->readAll(), nullptr, false);
206+
if(obj.is_discarded() || !obj.is_object())
207207
break;
208-
QJsonObject obj = json.object();
209-
QJsonObject obj_branches = obj["branches"].toObject();
208+
json obj_branches = obj["branches"];
210209

211210
// Parse data and assemble branch list
212-
QStringList branches;
213-
for(auto it=obj_branches.constBegin();it!=obj_branches.constEnd();++it)
214-
branches.append(it.key());
211+
std::vector<std::string> branches;
212+
for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it)
213+
branches.push_back(it.key());
215214

216215
// Get default branch
217-
#if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
218-
QString default_branch = obj["default_branch"].toString("master");
219-
#else
220-
QString default_branch = obj["default_branch"].toString();
221-
if ( default_branch.isEmpty () )
222-
{
223-
default_branch = "master";
224-
}
225-
#endif
216+
std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "master";
226217

227218
// Send branch list to anyone who is interested
228219
emit gotBranchList(branches, default_branch);
@@ -231,20 +222,19 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
231222
case RequestTypePush:
232223
{
233224
// Read and check results
234-
QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
235-
if(json.isNull() || !json.isObject())
225+
json obj = json::parse(reply->readAll(), nullptr, false);
226+
if(obj.is_discarded() || !obj.is_object())
236227
break;
237-
QJsonObject obj = json.object();
238228

239229
// Create or update the record in our local checkout database
240-
QString saveFileAs = localAdd(reply->url().fileName(), reply->property("certfile").toString(), obj["url"].toString(), obj["commit_id"].toString());
230+
QString saveFileAs = localAdd(reply->url().fileName(), reply->property("certfile").toString(), QString::fromStdString(obj["url"]), obj["commit_id"]);
241231

242232
// If the name of the source file and the name we're saving as differ, we're doing an initial push. In this case, copy the source file to
243233
// the destination path to avoid redownloading it when it's first used.
244234
if(saveFileAs != reply->property("source_file").toString())
245235
QFile::copy(reply->property("source_file").toString(), saveFileAs);
246236

247-
emit uploadFinished(obj["url"].toString());
237+
emit uploadFinished(obj["url"]);
248238
break;
249239
}
250240
}
@@ -480,7 +470,7 @@ void RemoteDatabase::push(const QString& filename, const QString& url, const QSt
480470
addPart(multipart, "licence", licence);
481471
addPart(multipart, "public", isPublic ? "true" : "false");
482472
addPart(multipart, "branch", branch);
483-
addPart(multipart, "commit", localLastCommitId(clientCert, url));
473+
addPart(multipart, "commit", QString::fromStdString(localLastCommitId(clientCert, url)));
484474
addPart(multipart, "force", forcePush ? "true" : "false");
485475
addPart(multipart, "lastmodified", last_modified.toString("yyyy-MM-dd'T'HH:mm:ss'Z'"));
486476

@@ -578,7 +568,7 @@ void RemoteDatabase::localAssureOpened()
578568
}
579569
}
580570

581-
QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl& url, const QString& new_commit_id)
571+
QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id)
582572
{
583573
// This function adds a new local database clone to our internal list. It does so by adding a single
584574
// new record to the remote dbs database. All the fields are extracted from the filename, the identity
@@ -595,8 +585,8 @@ QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl&
595585
identity = f.fileName();
596586

597587
// Check if this file has already been checked in
598-
QString last_commit_id = localLastCommitId(identity, url.toString());
599-
if(last_commit_id.isNull())
588+
std::string last_commit_id = localLastCommitId(identity, url.toString());
589+
if(last_commit_id.empty())
600590
{
601591
// The file hasn't been checked in yet. So add a new record for it.
602592

@@ -628,13 +618,13 @@ QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl&
628618
return QString();
629619
}
630620

631-
if(sqlite3_bind_text(stmt, 4, new_commit_id.toUtf8(), new_commit_id.toUtf8().length(), SQLITE_TRANSIENT))
621+
if(sqlite3_bind_text(stmt, 4, new_commit_id.c_str(), static_cast<int>(new_commit_id.size()), SQLITE_TRANSIENT))
632622
{
633623
sqlite3_finalize(stmt);
634624
return QString();
635625
}
636626

637-
if(sqlite3_bind_text(stmt, 5, filename.toUtf8(), filename.toUtf8().length(), SQLITE_TRANSIENT))
627+
if(sqlite3_bind_text(stmt, 5, filename.toUtf8(), filename.size(), SQLITE_TRANSIENT))
638628
{
639629
sqlite3_finalize(stmt);
640630
return QString();
@@ -662,7 +652,7 @@ QString RemoteDatabase::localAdd(QString filename, QString identity, const QUrl&
662652
if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK)
663653
return QString();
664654

665-
if(sqlite3_bind_text(stmt, 1, new_commit_id.toUtf8(), new_commit_id.toUtf8().length(), SQLITE_TRANSIENT))
655+
if(sqlite3_bind_text(stmt, 1, new_commit_id.c_str(), static_cast<int>(new_commit_id.size()), SQLITE_TRANSIENT))
666656
{
667657
sqlite3_finalize(stmt);
668658
return QString();
@@ -825,7 +815,7 @@ QString RemoteDatabase::localCheckFile(const QString& local_file)
825815
}
826816
}
827817

828-
QString RemoteDatabase::localLastCommitId(QString identity, const QUrl& url)
818+
std::string RemoteDatabase::localLastCommitId(QString identity, const QUrl& url)
829819
{
830820
// This function takes a file name and checks with which commit id we had checked out this file or last pushed it.
831821

@@ -835,32 +825,32 @@ QString RemoteDatabase::localLastCommitId(QString identity, const QUrl& url)
835825
QString sql = QString("SELECT commit_id FROM local WHERE identity=? AND url=?");
836826
sqlite3_stmt* stmt;
837827
if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, nullptr) != SQLITE_OK)
838-
return QString();
828+
return std::string();
839829

840830
QFileInfo f(identity); // Remove the path
841831
identity = f.fileName();
842832
if(sqlite3_bind_text(stmt, 1, identity.toUtf8(), identity.toUtf8().length(), SQLITE_TRANSIENT))
843833
{
844834
sqlite3_finalize(stmt);
845-
return QString();
835+
return std::string();
846836
}
847837

848838
if(sqlite3_bind_text(stmt, 2, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(),
849839
url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().size(), SQLITE_TRANSIENT))
850840
{
851841
sqlite3_finalize(stmt);
852-
return QString();
842+
return std::string();
853843
}
854844

855845
if(sqlite3_step(stmt) != SQLITE_ROW)
856846
{
857847
// If there was either an error or no record was found for this file name, stop here.
858848
sqlite3_finalize(stmt);
859-
return QString();
849+
return std::string();
860850
}
861851

862852
// Having come here we can assume that at least some local clone with the given file name
863-
QString local_commit_id = QString::fromUtf8(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
853+
std::string local_commit_id = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
864854
sqlite3_finalize(stmt);
865855

866856
return local_commit_id;

src/RemoteDatabase.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ class RemoteDatabase : public QObject
6161
// a directory listing or the licence list.
6262
void gotDirList(QString json, QVariant userdata);
6363
void gotCurrentVersion(QString version, QString url);
64-
void gotLicenceList(QMap<QString, QString> licences);
65-
void gotBranchList(QStringList branches, QString default_branch);
64+
void gotLicenceList(QMap<std::string, std::string> licences);
65+
void gotBranchList(std::vector<std::string> branches, std::string default_branch);
6666

6767
// The uploadFinished() signal is emitted when a push() call is finished, i.e. a database upload has completed.
68-
void uploadFinished(QString url);
68+
void uploadFinished(std::string url);
6969

7070
private:
7171
void gotEncrypted(QNetworkReply* reply);
@@ -77,10 +77,10 @@ class RemoteDatabase : public QObject
7777

7878
// Helper functions for managing the list of locally available databases
7979
void localAssureOpened();
80-
QString localAdd(QString filename, QString identity, const QUrl& url, const QString& new_commit_id);
80+
QString localAdd(QString filename, QString identity, const QUrl& url, const std::string& new_commit_id);
8181
QString localExists(const QUrl& url, QString identity);
8282
QString localCheckFile(const QString& local_file);
83-
QString localLastCommitId(QString clientCert, const QUrl& url);
83+
std::string localLastCommitId(QString clientCert, const QUrl& url);
8484

8585
// Helper functions for building multi-part HTTP requests
8686
void addPart(QHttpMultiPart* multipart, const QString& name, const QString& value);

0 commit comments

Comments
 (0)