Christophe Dumez
13 years ago
19 changed files with 825 additions and 412 deletions
@ -0,0 +1,333 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "btjson.h" |
||||||
|
#include "jsondict.h" |
||||||
|
#include "jsonlist.h" |
||||||
|
#include "misc.h" |
||||||
|
#include "qbtsession.h" |
||||||
|
#include "torrentpersistentdata.h" |
||||||
|
|
||||||
|
#include <QElapsedTimer> |
||||||
|
|
||||||
|
using namespace libtorrent; |
||||||
|
|
||||||
|
#define CACHED_VARIABLE(VARTYPE, VAR, DUR) \ |
||||||
|
static VARTYPE VAR; \ |
||||||
|
static QElapsedTimer cacheTimer; \ |
||||||
|
static bool initialized = false; \ |
||||||
|
if (initialized && !cacheTimer.hasExpired(DUR)) \ |
||||||
|
return VAR.toString(); \ |
||||||
|
initialized = true; \ |
||||||
|
cacheTimer.start(); \ |
||||||
|
VAR.clear() |
||||||
|
|
||||||
|
// Numerical constants
|
||||||
|
static const int CACHE_DURATION_MS = 1500; // 1500ms
|
||||||
|
|
||||||
|
// Torrent keys
|
||||||
|
static const char KEY_TORRENT_HASH[] = "hash"; |
||||||
|
static const char KEY_TORRENT_NAME[] = "name"; |
||||||
|
static const char KEY_TORRENT_SIZE[] = "size"; |
||||||
|
static const char KEY_TORRENT_PROGRESS[] = "progress"; |
||||||
|
static const char KEY_TORRENT_DLSPEED[] = "dlspeed"; |
||||||
|
static const char KEY_TORRENT_UPSPEED[] = "upspeed"; |
||||||
|
static const char KEY_TORRENT_PRIORITY[] = "priority"; |
||||||
|
static const char KEY_TORRENT_SEEDS[] = "num_seeds"; |
||||||
|
static const char KEY_TORRENT_LEECHS[] = "num_leechs"; |
||||||
|
static const char KEY_TORRENT_RATIO[] = "ratio"; |
||||||
|
static const char KEY_TORRENT_ETA[] = "eta"; |
||||||
|
static const char KEY_TORRENT_STATE[] = "state"; |
||||||
|
|
||||||
|
// Tracker keys
|
||||||
|
static const char KEY_TRACKER_URL[] = "url"; |
||||||
|
static const char KEY_TRACKER_STATUS[] = "status"; |
||||||
|
static const char KEY_TRACKER_MSG[] = "msg"; |
||||||
|
static const char KEY_TRACKER_PEERS[] = "num_peers"; |
||||||
|
|
||||||
|
// Torrent keys (Properties)
|
||||||
|
static const char KEY_PROP_SAVE_PATH[] = "save_path"; |
||||||
|
static const char KEY_PROP_CREATION_DATE[] = "creation_date"; |
||||||
|
static const char KEY_PROP_PIECE_SIZE[] = "piece_size"; |
||||||
|
static const char KEY_PROP_COMMENT[] = "comment"; |
||||||
|
static const char KEY_PROP_WASTED[] = "total_wasted"; |
||||||
|
static const char KEY_PROP_DOWNLOADED[] = "total_uploaded"; |
||||||
|
static const char KEY_PROP_UPLOADED[] = "total_downloaded"; |
||||||
|
static const char KEY_PROP_UP_LIMIT[] = "up_limit"; |
||||||
|
static const char KEY_PROP_DL_LIMIT[] = "dl_limit"; |
||||||
|
static const char KEY_PROP_TIME_ELAPSED[] = "time_elapsed"; |
||||||
|
static const char KEY_PROP_CONNECT_COUNT[] = "nb_connections"; |
||||||
|
static const char KEY_PROP_RATIO[] = "share_ratio"; |
||||||
|
|
||||||
|
// File keys
|
||||||
|
static const char KEY_FILE_NAME[] = "name"; |
||||||
|
static const char KEY_FILE_SIZE[] = "size"; |
||||||
|
static const char KEY_FILE_PROGRESS[] = "progress"; |
||||||
|
static const char KEY_FILE_PRIORITY[] = "priority"; |
||||||
|
static const char KEY_FILE_IS_SEED[] = "is_seed"; |
||||||
|
|
||||||
|
static JsonDict toJson(const QTorrentHandle& h) |
||||||
|
{ |
||||||
|
JsonDict ret; |
||||||
|
ret.add(KEY_TORRENT_HASH, h.hash()); |
||||||
|
ret.add(KEY_TORRENT_NAME, h.name()); |
||||||
|
ret.add(KEY_TORRENT_SIZE, misc::friendlyUnit(h.actual_size())); // FIXME: Should pass as Number, not formatted String (for sorting).
|
||||||
|
ret.add(KEY_TORRENT_PROGRESS, (double)h.progress()); |
||||||
|
ret.add(KEY_TORRENT_DLSPEED, misc::friendlyUnit(h.download_payload_rate(), true)); // FIXME: Should be passed as a Number
|
||||||
|
ret.add(KEY_TORRENT_UPSPEED, misc::friendlyUnit(h.upload_payload_rate(), true)); // FIXME: Should be passed as a Number
|
||||||
|
if (QBtSession::instance()->isQueueingEnabled() && h.queue_position() >= 0) |
||||||
|
ret.add(KEY_TORRENT_PRIORITY, QString::number(h.queue_position())); |
||||||
|
else |
||||||
|
ret.add(KEY_TORRENT_PRIORITY, "*"); |
||||||
|
QString seeds = QString::number(h.num_seeds()); |
||||||
|
if (h.num_complete() > 0) |
||||||
|
seeds += " ("+QString::number(h.num_complete())+")"; |
||||||
|
ret.add(KEY_TORRENT_SEEDS, seeds); |
||||||
|
QString leechs = QString::number(h.num_peers() - h.num_seeds()); |
||||||
|
if (h.num_incomplete() > 0) |
||||||
|
leechs += " ("+QString::number(h.num_incomplete())+")"; |
||||||
|
ret.add(KEY_TORRENT_LEECHS, leechs); |
||||||
|
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash()); |
||||||
|
ret.add(KEY_TORRENT_RATIO, (ratio > 100.) ? QString::fromUtf8("∞") : QString::number(ratio, 'f', 1)); |
||||||
|
QString eta; |
||||||
|
QString state; |
||||||
|
if (h.is_paused()) { |
||||||
|
if (h.has_error()) |
||||||
|
state = "error"; |
||||||
|
else |
||||||
|
state = h.is_seed() ? "pausedUP" : "pausedDL"; |
||||||
|
} else { |
||||||
|
if (QBtSession::instance()->isQueueingEnabled() && h.is_queued()) |
||||||
|
state = h.is_seed() ? "queuedUP" : "queuedDL"; |
||||||
|
else { |
||||||
|
switch (h.state()) { |
||||||
|
case torrent_status::finished: |
||||||
|
case torrent_status::seeding: |
||||||
|
state = h.upload_payload_rate() > 0 ? "uploading" : "stalledUP"; |
||||||
|
break; |
||||||
|
case torrent_status::allocating: |
||||||
|
case torrent_status::checking_files: |
||||||
|
case torrent_status::queued_for_checking: |
||||||
|
case torrent_status::checking_resume_data: |
||||||
|
state = h.is_seed() ? "checkingUP" : "checkingDL"; |
||||||
|
break; |
||||||
|
case torrent_status::downloading: |
||||||
|
case torrent_status::downloading_metadata: |
||||||
|
state = h.download_payload_rate() > 0 ? "downloading" : "stalledDL"; |
||||||
|
eta = misc::userFriendlyDuration(QBtSession::instance()->getETA(h.hash())); |
||||||
|
break; |
||||||
|
default: |
||||||
|
qWarning("Unrecognized torrent status, should not happen!!! status was %d", h.state()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
ret.add(KEY_TORRENT_ETA, eta.isEmpty() ? QString::fromUtf8("∞") : eta); |
||||||
|
ret.add(KEY_TORRENT_STATE, state); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the torrents in JSON format. |
||||||
|
* |
||||||
|
* The return value is a JSON-formatted list of dictionaries. |
||||||
|
* The dictionary keys are: |
||||||
|
* - "hash": Torrent hash |
||||||
|
* - "name": Torrent name |
||||||
|
* - "size": Torrent size |
||||||
|
* - "progress: Torrent progress |
||||||
|
* - "dlspeed": Torrent download speed |
||||||
|
* - "upspeed": Torrent upload speed |
||||||
|
* - "priority": Torrent priority ('*' if queuing is disabled) |
||||||
|
* - "num_seeds": Torrent seed count |
||||||
|
* - "num_leechs": Torrent leecher count |
||||||
|
* - "ratio": Torrent share ratio |
||||||
|
* - "eta": Torrent ETA |
||||||
|
* - "state": Torrent state |
||||||
|
*/ |
||||||
|
QString btjson::getTorrents() |
||||||
|
{ |
||||||
|
CACHED_VARIABLE(JsonList, torrent_list, CACHE_DURATION_MS); |
||||||
|
std::vector<torrent_handle> torrents = QBtSession::instance()->getTorrents(); |
||||||
|
std::vector<torrent_handle>::const_iterator it = torrents.begin(); |
||||||
|
std::vector<torrent_handle>::const_iterator end = torrents.end(); |
||||||
|
for( ; it != end; ++it) { |
||||||
|
torrent_list.append(toJson(QTorrentHandle(*it))); |
||||||
|
} |
||||||
|
return torrent_list.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the trackers for a torrent in JSON format. |
||||||
|
* |
||||||
|
* The return value is a JSON-formatted list of dictionaries. |
||||||
|
* The dictionary keys are: |
||||||
|
* - "url": Tracker URL |
||||||
|
* - "status": Tracker status |
||||||
|
* - "num_peers": Tracker peer count |
||||||
|
* - "msg": Tracker message (last) |
||||||
|
*/ |
||||||
|
QString btjson::getTrackersForTorrent(const QString& hash) |
||||||
|
{ |
||||||
|
CACHED_VARIABLE(JsonList, tracker_list, CACHE_DURATION_MS); |
||||||
|
try { |
||||||
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
||||||
|
QHash<QString, TrackerInfos> trackers_data = QBtSession::instance()->getTrackersInfo(hash); |
||||||
|
std::vector<announce_entry> vect_trackers = h.trackers(); |
||||||
|
std::vector<announce_entry>::const_iterator it = vect_trackers.begin(); |
||||||
|
std::vector<announce_entry>::const_iterator end = vect_trackers.end(); |
||||||
|
for (; it != end; ++it) { |
||||||
|
JsonDict tracker_dict; |
||||||
|
const QString tracker_url = misc::toQString(it->url); |
||||||
|
tracker_dict.add(KEY_TRACKER_URL, tracker_url); |
||||||
|
const TrackerInfos data = trackers_data.value(tracker_url, TrackerInfos(tracker_url)); |
||||||
|
QString status; |
||||||
|
if (it->verified) |
||||||
|
status = tr("Working"); |
||||||
|
else { |
||||||
|
if (it->updating && it->fails == 0) |
||||||
|
status = tr("Updating..."); |
||||||
|
else |
||||||
|
status = it->fails > 0 ? tr("Not working") : tr("Not contacted yet"); |
||||||
|
} |
||||||
|
tracker_dict.add(KEY_TRACKER_STATUS, status); |
||||||
|
tracker_dict.add(KEY_TRACKER_PEERS, QString::number(trackers_data.value(tracker_url, TrackerInfos(tracker_url)).num_peers)); |
||||||
|
tracker_dict.add(KEY_TRACKER_MSG, data.last_message.trimmed()); |
||||||
|
|
||||||
|
tracker_list.append(tracker_dict); |
||||||
|
} |
||||||
|
} catch(const std::exception&) { |
||||||
|
qWarning() << "getTrackersForTorrent() called with invalid torrent"; |
||||||
|
return QString(); |
||||||
|
} |
||||||
|
|
||||||
|
return tracker_list.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the properties for a torrent in JSON format. |
||||||
|
* |
||||||
|
* The return value is a JSON-formatted dictionary. |
||||||
|
* The dictionary keys are: |
||||||
|
* - "save_path": Torrent save path |
||||||
|
* - "creation_date": Torrent creation date |
||||||
|
* - "piece_size": Torrent piece size |
||||||
|
* - "comment": Torrent comment |
||||||
|
* - "total_wasted": Total data wasted for torrent |
||||||
|
* - "total_uploaded": Total data uploaded for torrent |
||||||
|
* - "total_downloaded": Total data uploaded for torrent |
||||||
|
* - "up_limit": Torrent upload limit |
||||||
|
* - "dl_limit": Torrent download limit |
||||||
|
* - "time_elapsed": Torrent elapsed time |
||||||
|
* - "nb_connections": Torrent connection count |
||||||
|
* - "share_ratio": Torrent share ratio |
||||||
|
*/ |
||||||
|
QString btjson::getPropertiesForTorrent(const QString& hash) |
||||||
|
{ |
||||||
|
CACHED_VARIABLE(JsonDict, data, CACHE_DURATION_MS); |
||||||
|
try { |
||||||
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
||||||
|
|
||||||
|
if (!h.has_metadata()) |
||||||
|
return QString(); |
||||||
|
|
||||||
|
// Save path
|
||||||
|
QString save_path = TorrentPersistentData::getSavePath(hash); |
||||||
|
if (save_path.isEmpty()) |
||||||
|
save_path = h.save_path(); |
||||||
|
data.add(KEY_PROP_SAVE_PATH, save_path); |
||||||
|
data.add(KEY_PROP_CREATION_DATE, h.creation_date()); |
||||||
|
data.add(KEY_PROP_PIECE_SIZE, misc::friendlyUnit(h.piece_length())); |
||||||
|
data.add(KEY_PROP_COMMENT, h.comment()); |
||||||
|
data.add(KEY_PROP_WASTED, misc::friendlyUnit(h.total_failed_bytes() + h.total_redundant_bytes())); |
||||||
|
data.add(KEY_PROP_UPLOADED, QString(misc::friendlyUnit(h.all_time_upload()) + " (" + misc::friendlyUnit(h.total_payload_upload()) + " " + tr("this session") + ")")); |
||||||
|
data.add(KEY_PROP_DOWNLOADED, QString(misc::friendlyUnit(h.all_time_download()) + " (" + misc::friendlyUnit(h.total_payload_download()) + " " + tr("this session") + ")")); |
||||||
|
if (h.upload_limit() <= 0) |
||||||
|
data.add(KEY_PROP_UPLOADED, QString::fromUtf8("∞")); |
||||||
|
else |
||||||
|
data.add(KEY_PROP_UPLOADED, misc::friendlyUnit(h.upload_limit(), true)); |
||||||
|
if (h.download_limit() <= 0) |
||||||
|
data.add(KEY_PROP_DOWNLOADED, QString::fromUtf8("∞")); |
||||||
|
else |
||||||
|
data.add(KEY_PROP_DOWNLOADED, misc::friendlyUnit(h.download_limit(), true)); |
||||||
|
QString elapsed_txt = misc::userFriendlyDuration(h.active_time()); |
||||||
|
if (h.is_seed()) |
||||||
|
elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")"; |
||||||
|
data.add(KEY_PROP_TIME_ELAPSED, elapsed_txt); |
||||||
|
data.add(KEY_PROP_CONNECT_COUNT, QString(QString::number(h.num_connections()) + " (" + tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit())) + ")")); |
||||||
|
const qreal ratio = QBtSession::instance()->getRealRatio(h.hash()); |
||||||
|
data.add(KEY_PROP_RATIO, ratio > 100. ? QString::fromUtf8("∞") : QString::number(ratio, 'f', 1)); |
||||||
|
} catch(const std::exception&) { |
||||||
|
return QString(); |
||||||
|
} |
||||||
|
|
||||||
|
return data.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the files in a torrent in JSON format. |
||||||
|
* |
||||||
|
* The return value is a JSON-formatted list of dictionaries. |
||||||
|
* The dictionary keys are: |
||||||
|
* - "name": File name |
||||||
|
* - "size": File size |
||||||
|
* - "progress": File progress |
||||||
|
* - "priority": File priority |
||||||
|
* - "is_seed": Flag indicating if torrent is seeding/complete |
||||||
|
*/ |
||||||
|
QString btjson::getFilesForTorrent(const QString& hash) |
||||||
|
{ |
||||||
|
CACHED_VARIABLE(JsonList, file_list, CACHE_DURATION_MS); |
||||||
|
try { |
||||||
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
||||||
|
if (!h.has_metadata()) |
||||||
|
return QString(); |
||||||
|
|
||||||
|
const std::vector<int> priorities = h.file_priorities(); |
||||||
|
std::vector<size_type> fp; |
||||||
|
h.file_progress(fp); |
||||||
|
for (int i = 0; i < h.num_files(); ++i) { |
||||||
|
JsonDict file_dict; |
||||||
|
file_dict.add(KEY_FILE_NAME, h.filename_at(i)); |
||||||
|
const size_type size = h.filesize_at(i); |
||||||
|
file_dict.add(KEY_FILE_SIZE, misc::friendlyUnit(size)); |
||||||
|
file_dict.add(KEY_FILE_PROGRESS, (size > 0) ? (fp[i] / (double) size) : 1.); |
||||||
|
file_dict.add(KEY_FILE_PRIORITY, priorities[i]); |
||||||
|
if (i == 0) |
||||||
|
file_dict.add(KEY_FILE_IS_SEED, h.is_seed()); |
||||||
|
|
||||||
|
file_list.append(file_dict); |
||||||
|
} |
||||||
|
} catch (const std::exception&) { |
||||||
|
return QString(); |
||||||
|
} |
||||||
|
|
||||||
|
return file_list.toString(); |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef BTJSON_H |
||||||
|
#define BTJSON_H |
||||||
|
|
||||||
|
#include <QCoreApplication> |
||||||
|
#include <QString> |
||||||
|
|
||||||
|
class btjson { |
||||||
|
Q_DECLARE_TR_FUNCTIONS(misc) |
||||||
|
|
||||||
|
private: |
||||||
|
btjson() {} |
||||||
|
|
||||||
|
public: |
||||||
|
static QString getTorrents(); |
||||||
|
static QString getTrackersForTorrent(const QString& hash); |
||||||
|
static QString getPropertiesForTorrent(const QString& hash); |
||||||
|
static QString getFilesForTorrent(const QString& hash); |
||||||
|
}; // class btjson
|
||||||
|
|
||||||
|
#endif // BTJSON_H
|
@ -0,0 +1,181 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2006-2012 Ishan Arora and Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "json.h" |
||||||
|
|
||||||
|
#include <QStringList> |
||||||
|
#include <QVariantMap> |
||||||
|
|
||||||
|
QString json::toJson(const QVariant& v) { |
||||||
|
if (v.isNull()) |
||||||
|
return "null"; |
||||||
|
switch(v.type()) |
||||||
|
{ |
||||||
|
case QVariant::Bool: |
||||||
|
case QVariant::Double: |
||||||
|
case QVariant::Int: |
||||||
|
case QVariant::LongLong: |
||||||
|
case QVariant::UInt: |
||||||
|
case QVariant::ULongLong: |
||||||
|
return v.value<QString>(); |
||||||
|
case QVariant::StringList: |
||||||
|
case QVariant::List: { |
||||||
|
QStringList strList; |
||||||
|
foreach (const QVariant &var, v.toList()) { |
||||||
|
strList << toJson(var); |
||||||
|
} |
||||||
|
return "["+strList.join(",")+"]"; |
||||||
|
} |
||||||
|
case QVariant::String: { |
||||||
|
QString s = v.value<QString>(); |
||||||
|
QString result = "\""; |
||||||
|
for (int i=0; i<s.size(); ++i) { |
||||||
|
const QChar ch = s[i]; |
||||||
|
switch(ch.toAscii()) |
||||||
|
{ |
||||||
|
case '\b': |
||||||
|
result += "\\b"; |
||||||
|
break; |
||||||
|
case '\f': |
||||||
|
result += "\\f"; |
||||||
|
break; |
||||||
|
case '\n': |
||||||
|
result += "\\n"; |
||||||
|
break; |
||||||
|
case '\r': |
||||||
|
result += "\\r"; |
||||||
|
break; |
||||||
|
case '\t': |
||||||
|
result += "\\t"; |
||||||
|
break; |
||||||
|
case '\"': |
||||||
|
case '\'': |
||||||
|
case '\\': |
||||||
|
case '&': |
||||||
|
result += '\\'; |
||||||
|
case '\0': |
||||||
|
default: |
||||||
|
result += ch; |
||||||
|
} |
||||||
|
} |
||||||
|
result += "\""; |
||||||
|
return result; |
||||||
|
} |
||||||
|
default: |
||||||
|
qDebug("Unknown QVariantType: %d", (int)v.type()); |
||||||
|
return "undefined"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
|
QString json::toJson(const QVariantMap& m) { |
||||||
|
QStringList vlist; |
||||||
|
QVariantMap::ConstIterator it; |
||||||
|
for (it = m.constBegin(); it != m.constEnd(); it++) { |
||||||
|
vlist << toJson(it.key())+":"+toJson(it.value()); |
||||||
|
} |
||||||
|
return "{"+vlist.join(",")+"}"; |
||||||
|
} |
||||||
|
|
||||||
|
QVariantMap json::fromJson(const QString& json) { |
||||||
|
qDebug("JSON is %s", qPrintable(json)); |
||||||
|
QVariantMap m; |
||||||
|
if (json.startsWith("{") && json.endsWith("}")) { |
||||||
|
QStringList couples; |
||||||
|
QString tmp = ""; |
||||||
|
bool in_list = false; |
||||||
|
foreach (const QChar &c, json.mid(1, json.length()-2)) { |
||||||
|
if (c == ',' && !in_list) { |
||||||
|
couples << tmp; |
||||||
|
tmp = ""; |
||||||
|
} else { |
||||||
|
if (c == '[') |
||||||
|
in_list = true; |
||||||
|
else if (c == ']') |
||||||
|
in_list = false; |
||||||
|
tmp += c; |
||||||
|
} |
||||||
|
} |
||||||
|
if (!tmp.isEmpty()) couples << tmp; |
||||||
|
|
||||||
|
foreach (const QString &couple, couples) { |
||||||
|
QStringList parts = couple.split(":"); |
||||||
|
if (parts.size() != 2) continue; |
||||||
|
QString key = parts.first(); |
||||||
|
if (key.startsWith("\"") && key.endsWith("\"")) { |
||||||
|
key = key.mid(1, key.length()-2); |
||||||
|
} |
||||||
|
QString value_str = parts.last(); |
||||||
|
QVariant value; |
||||||
|
if (value_str.startsWith("[") && value_str.endsWith("]")) { |
||||||
|
value_str = value_str.mid(1, value_str.length()-2); |
||||||
|
QStringList list_elems = value_str.split(",", QString::SkipEmptyParts); |
||||||
|
QVariantList varlist; |
||||||
|
foreach (const QString &list_val, list_elems) { |
||||||
|
if (list_val.startsWith("\"") && list_val.endsWith("\"")) { |
||||||
|
varlist << list_val.mid(1, list_val.length()-2).replace("\\n", "\n"); |
||||||
|
} else { |
||||||
|
varlist << list_val.toInt(); |
||||||
|
} |
||||||
|
} |
||||||
|
value = varlist; |
||||||
|
} else { |
||||||
|
if (value_str.startsWith("\"") && value_str.endsWith("\"")) { |
||||||
|
value_str = value_str.mid(1, value_str.length()-2).replace("\\n", "\n"); |
||||||
|
value = value_str; |
||||||
|
} else { |
||||||
|
if (value_str.compare("false", Qt::CaseInsensitive) == 0) |
||||||
|
value = false; |
||||||
|
else if (value_str.compare("true", Qt::CaseInsensitive) == 0) |
||||||
|
value = true; |
||||||
|
else |
||||||
|
value = value_str.toInt(); |
||||||
|
} |
||||||
|
} |
||||||
|
m.insert(key, value); |
||||||
|
qDebug("%s:%s", key.toLocal8Bit().data(), value_str.toLocal8Bit().data()); |
||||||
|
} |
||||||
|
} |
||||||
|
return m; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
|
QString json::toJson(const QList<QVariantMap>& v) { |
||||||
|
QStringList res; |
||||||
|
foreach (QVariantMap m, v) { |
||||||
|
QStringList vlist; |
||||||
|
QVariantMap::ConstIterator it; |
||||||
|
for (it = m.constBegin(); it != m.constEnd(); it++) { |
||||||
|
vlist << toJson(it.key())+":"+toJson(it.value()); |
||||||
|
} |
||||||
|
res << "{"+vlist.join(",")+"}"; |
||||||
|
} |
||||||
|
return "["+res.join(",")+"]"; |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "jsondict.h" |
||||||
|
#include "json.h" |
||||||
|
|
||||||
|
JsonDict::JsonDict(): m_dirty(false) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void JsonDict::clear() |
||||||
|
{ |
||||||
|
m_items.clear(); |
||||||
|
m_dirty = true; |
||||||
|
} |
||||||
|
|
||||||
|
void JsonDict::add(const QString& key, const QVariant& value) |
||||||
|
{ |
||||||
|
m_items.append("\"" + key + "\":" + json::toJson(value)); |
||||||
|
m_dirty = true; |
||||||
|
} |
||||||
|
|
||||||
|
const QString& JsonDict::toString() const |
||||||
|
{ |
||||||
|
static QString str; |
||||||
|
if (m_dirty) { |
||||||
|
str = "{" + m_items.join(",") + "}"; |
||||||
|
m_dirty = false; |
||||||
|
} |
||||||
|
return str; |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef JSONDICT_H |
||||||
|
#define JSONDICT_H |
||||||
|
|
||||||
|
#include <QStringList> |
||||||
|
|
||||||
|
class JsonDict |
||||||
|
{ |
||||||
|
public: |
||||||
|
JsonDict(); |
||||||
|
void clear(); |
||||||
|
void add(const QString& key, const QVariant& value); |
||||||
|
const QString& toString() const; |
||||||
|
|
||||||
|
private: |
||||||
|
mutable bool m_dirty; |
||||||
|
QStringList m_items; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // JSONDICT_H
|
@ -0,0 +1,64 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "jsonlist.h" |
||||||
|
#include "json.h" |
||||||
|
|
||||||
|
JsonList::JsonList() : m_dirty(false) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
const QString& JsonList::toString() const |
||||||
|
{ |
||||||
|
static QString str; |
||||||
|
if (m_dirty) { |
||||||
|
str = "[" + m_items.join(",") + "]"; |
||||||
|
m_dirty = false; |
||||||
|
} |
||||||
|
return str; |
||||||
|
} |
||||||
|
|
||||||
|
void JsonList::clear() |
||||||
|
{ |
||||||
|
m_items.clear(); |
||||||
|
m_dirty = true; |
||||||
|
} |
||||||
|
|
||||||
|
void JsonList::append(const QVariant& val) |
||||||
|
{ |
||||||
|
m_items.append(json::toJson(val)); |
||||||
|
m_dirty = true; |
||||||
|
} |
||||||
|
|
||||||
|
void JsonList::append(const JsonDict& dict) |
||||||
|
{ |
||||||
|
m_items.append(dict.toString()); |
||||||
|
m_dirty = true; |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt4 and libtorrent. |
||||||
|
* Copyright (C) 2012, Christophe Dumez |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* modify file(s), you may extend this exception to your version of the file(s), |
||||||
|
* but you are not obligated to do so. If you do not wish to do so, delete this |
||||||
|
* exception statement from your version. |
||||||
|
* |
||||||
|
* Contact : chris@qbittorrent.org |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef JSONLIST_H |
||||||
|
#define JSONLIST_H |
||||||
|
|
||||||
|
#include <QStringList> |
||||||
|
#include "jsondict.h" |
||||||
|
|
||||||
|
class JsonList |
||||||
|
{ |
||||||
|
public: |
||||||
|
JsonList(); |
||||||
|
const QString& toString() const; |
||||||
|
void clear(); |
||||||
|
void append(const QVariant& val); |
||||||
|
void append(const JsonDict& dict); |
||||||
|
|
||||||
|
private: |
||||||
|
mutable bool m_dirty; |
||||||
|
QStringList m_items; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // JSONLIST_H
|
Loading…
Reference in new issue