summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-06-18 14:47:09 +0000
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2010-06-18 14:47:09 +0000
commit8ba97188ce42be38b5427e9bd70bb7f5ba8238f9 (patch)
tree6cba1ad1496b6865c215881e7a0f21c009287912 /src
parent98dc02192d4b10eb6057a7d6a724b2e05a5767ef (diff)
2010-06-18 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Introduced ValueBase class, which is a replacement of BDE. In this change ValueBase is used instead of BDE except DHT messages, UTMetadata messages and XML-RPC. They'll be replaced in the later commits. DownloadContext::_attrs is now ContextAttribute rather than BDE. * src/ActivePeerConnectionCommand.cc * src/AnnounceList.cc * src/AnnounceList.h * src/BtDependency.cc * src/BtRegistry.cc * src/BtSetup.cc * src/ConsoleStatCalc.cc * src/ContextAttribute.h * src/DefaultBtAnnounce.cc * src/DefaultBtInteractive.cc * src/DownloadContext.cc * src/DownloadContext.h * src/HandshakeExtensionMessage.cc * src/InitiateConnectionCommand.cc * src/LpdReceiveMessageCommand.cc * src/MSEHandshake.cc * src/Makefile.am * src/Makefile.in * src/PeerInteractionCommand.cc * src/PeerListProcessor.h * src/ProtocolDetector.cc * src/RequestGroup.cc * src/RequestGroupMan.cc * src/TorrentAttribute.h * src/TrackerWatcherCommand.cc * src/UTMetadataDataExtensionMessage.cc * src/UTMetadataPostDownloadHandler.cc * src/UTMetadataRequestExtensionMessage.cc * src/ValueBase.cc * src/ValueBase.h * src/XmlRpcMethodImpl.cc * src/XmlRpcMethodImpl.h * src/bencode2.cc * src/bencode2.h * src/bittorrent_helper.cc * src/bittorrent_helper.h * src/download_helper.cc * src/magnet.cc * src/magnet.h * test/AnnounceListTest.cc * test/Bencode2Test.cc * test/BencodeTest.cc * test/BittorrentHelperTest.cc * test/BtDependencyTest.cc * test/BtRegistryTest.cc * test/DefaultBtAnnounceTest.cc * test/DefaultBtProgressInfoFileTest.cc * test/HandshakeExtensionMessageTest.cc * test/MSEHandshakeTest.cc * test/MagnetTest.cc * test/Makefile.am * test/Makefile.in * test/RequestGroupManTest.cc * test/UTMetadataDataExtensionMessageTest.cc * test/UTMetadataPostDownloadHandlerTest.cc * test/UTMetadataRequestExtensionMessageTest.cc * test/ValueBaseTest.cc * test/XmlRpcMethodTest.cc
Diffstat (limited to 'src')
-rw-r--r--src/ActivePeerConnectionCommand.cc4
-rw-r--r--src/AnnounceList.cc34
-rw-r--r--src/AnnounceList.h7
-rw-r--r--src/BtDependency.cc4
-rw-r--r--src/BtRegistry.cc7
-rw-r--r--src/BtSetup.cc11
-rw-r--r--src/ConsoleStatCalc.cc3
-rw-r--r--src/ContextAttribute.h44
-rw-r--r--src/DefaultBtAnnounce.cc59
-rw-r--r--src/DefaultBtInteractive.cc7
-rw-r--r--src/DownloadContext.cc36
-rw-r--r--src/DownloadContext.h12
-rw-r--r--src/HandshakeExtensionMessage.cc14
-rw-r--r--src/InitiateConnectionCommand.cc1
-rw-r--r--src/LpdReceiveMessageCommand.cc13
-rw-r--r--src/MSEHandshake.cc7
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.in33
-rw-r--r--src/PeerInteractionCommand.cc10
-rw-r--r--src/PeerListProcessor.h59
-rw-r--r--src/ProtocolDetector.cc1
-rw-r--r--src/RequestGroup.cc30
-rw-r--r--src/RequestGroupMan.cc1
-rw-r--r--src/TorrentAttribute.h66
-rw-r--r--src/TrackerWatcherCommand.cc10
-rw-r--r--src/UTMetadataDataExtensionMessage.cc5
-rw-r--r--src/UTMetadataPostDownloadHandler.cc8
-rw-r--r--src/UTMetadataRequestExtensionMessage.cc18
-rw-r--r--src/ValueBase.cc347
-rw-r--r--src/ValueBase.h288
-rw-r--r--src/XmlRpcMethodImpl.cc45
-rw-r--r--src/XmlRpcMethodImpl.h8
-rw-r--r--src/bencode2.cc263
-rw-r--r--src/bencode2.h75
-rw-r--r--src/bittorrent_helper.cc463
-rw-r--r--src/bittorrent_helper.h29
-rw-r--r--src/download_helper.cc5
-rw-r--r--src/magnet.cc22
-rw-r--r--src/magnet.h13
39 files changed, 1630 insertions, 438 deletions
diff --git a/src/ActivePeerConnectionCommand.cc b/src/ActivePeerConnectionCommand.cc
index 7d17b447..f7bfc79b 100644
--- a/src/ActivePeerConnectionCommand.cc
+++ b/src/ActivePeerConnectionCommand.cc
@@ -89,8 +89,8 @@ bool ActivePeerConnectionCommand::execute() {
_requestGroup->getMaxDownloadSpeedLimit();
const unsigned int maxUploadLimit = _requestGroup->getMaxUploadSpeedLimit();
unsigned int thresholdSpeed;
- if(_requestGroup->getDownloadContext()->
- getAttribute(bittorrent::BITTORRENT).containsKey(bittorrent::METADATA)) {
+ if(!bittorrent::getTorrentAttrs
+ (_requestGroup->getDownloadContext())->metadata.empty()) {
thresholdSpeed =
_requestGroup->getOption()->getAsInt(PREF_BT_REQUEST_PEER_SPEED_LIMIT);
} else {
diff --git a/src/AnnounceList.cc b/src/AnnounceList.cc
index d417a08a..c3ea52be 100644
--- a/src/AnnounceList.cc
+++ b/src/AnnounceList.cc
@@ -49,7 +49,8 @@ const std::string AnnounceList::STOPPED("stopped");
const std::string AnnounceList::COMPLETED("completed");
-AnnounceList::AnnounceList(const BDE& announceList):
+AnnounceList::AnnounceList
+(const std::vector<std::vector<std::string> >& announceList):
_currentTrackerInitialized(false) {
reconfigure(announceList);
}
@@ -60,30 +61,19 @@ AnnounceList::AnnounceList
resetIterator();
}
-void AnnounceList::reconfigure(const BDE& announceList)
+void AnnounceList::reconfigure
+(const std::vector<std::vector<std::string> >& announceList)
{
- if(announceList.isList()) {
- for(BDE::List::const_iterator itr = announceList.listBegin(),
- eoi = announceList.listEnd(); itr != eoi; ++itr) {
- const BDE& elemList = *itr;
- if(!elemList.isList()) {
- continue;
- }
- std::deque<std::string> urls;
- for(BDE::List::const_iterator elemItr = elemList.listBegin(),
- eoi2 = elemList.listEnd(); elemItr != eoi2; ++elemItr) {
- const BDE& data = *elemItr;
- if(data.isString()) {
- urls.push_back(data.s());
- }
- }
- if(!urls.empty()) {
- SharedHandle<AnnounceTier> tier(new AnnounceTier(urls));
- _tiers.push_back(tier);
- }
+ for(std::vector<std::vector<std::string> >::const_iterator itr =
+ announceList.begin(), eoi = announceList.end(); itr != eoi; ++itr) {
+ if((*itr).empty()) {
+ continue;
}
- resetIterator();
+ std::deque<std::string> urls((*itr).begin(), (*itr).end());
+ SharedHandle<AnnounceTier> tier(new AnnounceTier(urls));
+ _tiers.push_back(tier);
}
+ resetIterator();
}
void AnnounceList::reconfigure(const std::string& url) {
diff --git a/src/AnnounceList.h b/src/AnnounceList.h
index 0349b580..394475c9 100644
--- a/src/AnnounceList.h
+++ b/src/AnnounceList.h
@@ -38,11 +38,10 @@
#include "common.h"
#include "SharedHandle.h"
#include "AnnounceTier.h"
+#include "ValueBase.h"
namespace aria2 {
-class BDE;
-
class AnnounceList {
public:
private:
@@ -56,10 +55,10 @@ private:
(const std::deque<SharedHandle<AnnounceTier> >::iterator& itr);
public:
AnnounceList():_currentTrackerInitialized(false) {}
- AnnounceList(const BDE& announceList);
+ AnnounceList(const std::vector<std::vector<std::string> >& announceList);
AnnounceList(const std::deque<SharedHandle<AnnounceTier> >& tiers);
- void reconfigure(const BDE& announceList);
+ void reconfigure(const std::vector<std::vector<std::string> >& announceList);
void reconfigure(const std::string& url);
size_t countTier() const {
diff --git a/src/BtDependency.cc b/src/BtDependency.cc
index 643b346d..54ac6125 100644
--- a/src/BtDependency.cc
+++ b/src/BtDependency.cc
@@ -85,8 +85,8 @@ bool BtDependency::resolve()
diskAdaptor->openExistingFile();
std::string content = util::toString(diskAdaptor);
if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
- const BDE& attrs =
- dependee->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
+ SharedHandle<TorrentAttribute> attrs =
+ bittorrent::getTorrentAttrs(dependee->getDownloadContext());
bittorrent::loadFromMemory
(bittorrent::metadata2Torrent(content, attrs), context, "default");
} else {
diff --git a/src/BtRegistry.cc b/src/BtRegistry.cc
index 05838bdf..debfb0b1 100644
--- a/src/BtRegistry.cc
+++ b/src/BtRegistry.cc
@@ -56,13 +56,12 @@ BtRegistry::getDownloadContext(const std::string& infoHash) const
SharedHandle<DownloadContext> dctx;
for(std::map<gid_t, BtObject>::const_iterator i = _pool.begin(),
eoi = _pool.end(); i != eoi; ++i) {
- const BDE& attrs =
- (*i).second._downloadContext->getAttribute(bittorrent::BITTORRENT);
- if(attrs[bittorrent::INFO_HASH].s() == infoHash) {
+ if(bittorrent::getTorrentAttrs((*i).second._downloadContext)->infoHash ==
+ infoHash) {
dctx = (*i).second._downloadContext;
break;
}
- }
+ }
return dctx;
}
diff --git a/src/BtSetup.cc b/src/BtSetup.cc
index 3da46902..d3e0115f 100644
--- a/src/BtSetup.cc
+++ b/src/BtSetup.cc
@@ -73,6 +73,7 @@
#include "FileAllocationEntry.h"
#include "CheckIntegrityEntry.h"
#include "ServerStatMan.h"
+#include "DlAbortEx.h"
namespace aria2 {
@@ -86,9 +87,9 @@ void BtSetup::setup(std::vector<Command*>& commands,
if(!requestGroup->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)){
return;
}
- const BDE& torrentAttrs =
- requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
- bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(requestGroup->getDownloadContext());
+ bool metadataGetMode = torrentAttrs->metadata.empty();
BtObject btObject = e->getBtRegistry()->get(requestGroup->getGID());
SharedHandle<PieceStorage> pieceStorage = btObject._pieceStorage;
SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
@@ -125,7 +126,7 @@ void BtSetup::setup(std::vector<Command*>& commands,
commands.push_back(c);
}
- if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) &&
+ if((metadataGetMode || !torrentAttrs->privateTorrent) &&
DHTSetup::initialized()) {
DHTGetPeersCommand* command =
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
@@ -179,7 +180,7 @@ void BtSetup::setup(std::vector<Command*>& commands,
btRuntime->setListenPort(listenCommand->getPort());
}
if(option->getAsBool(PREF_BT_ENABLE_LPD) &&
- (metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0)) {
+ (metadataGetMode || !torrentAttrs->privateTorrent)) {
if(LpdReceiveMessageCommand::getNumInstance() == 0) {
_logger->info("Initializing LpdMessageReceiver.");
SharedHandle<LpdMessageReceiver> receiver
diff --git a/src/ConsoleStatCalc.cc b/src/ConsoleStatCalc.cc
index 53dc0560..29c55c40 100644
--- a/src/ConsoleStatCalc.cc
+++ b/src/ConsoleStatCalc.cc
@@ -89,8 +89,7 @@ static void printProgress
#ifdef ENABLE_BITTORRENT
if(rg->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT) &&
- rg->getDownloadContext()->getAttribute(bittorrent::BITTORRENT)
- .containsKey(bittorrent::METADATA) &&
+ !bittorrent::getTorrentAttrs(rg->getDownloadContext())->metadata.empty() &&
rg->downloadFinished()) {
o << "SEEDING" << "(" << "ratio:";
if(rg->getCompletedLength() > 0) {
diff --git a/src/ContextAttribute.h b/src/ContextAttribute.h
new file mode 100644
index 00000000..9ca25b8d
--- /dev/null
+++ b/src/ContextAttribute.h
@@ -0,0 +1,44 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef D_CONTEXT_ATTRIBUTE_H
+#define D_CONTEXT_ATTRIBUTE_H
+
+#include "common.h"
+
+struct ContextAttribute {
+ virtual ~ContextAttribute() {}
+};
+
+#endif // D_CONTEXT_ATTRIBUTE_H
diff --git a/src/DefaultBtAnnounce.cc b/src/DefaultBtAnnounce.cc
index 2a59f769..416bb0c7 100644
--- a/src/DefaultBtAnnounce.cc
+++ b/src/DefaultBtAnnounce.cc
@@ -50,7 +50,7 @@
#include "StringFormat.h"
#include "A2STR.h"
#include "Request.h"
-#include "bencode.h"
+#include "bencode2.h"
#include "bittorrent_helper.h"
#include "wallclock.h"
@@ -67,9 +67,7 @@ DefaultBtAnnounce::DefaultBtAnnounce
_userDefinedInterval(0),
_complete(0),
_incomplete(0),
- _announceList
- (downloadContext->getAttribute
- (bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST]),
+ _announceList(bittorrent::getTorrentAttrs(downloadContext)->announceList),
_option(option),
_logger(LogFactory::getInstance()),
_randomizer(SimpleRandomizer::getInstance())
@@ -219,37 +217,38 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
if(_logger->debug()) {
_logger->debug("Now processing tracker response.");
}
- const BDE dict =
- bencode::decode(trackerResponse, trackerResponseLength);
- if(!dict.isDict()) {
+ SharedHandle<ValueBase> decodedValue =
+ bencode2::decode(trackerResponse, trackerResponseLength);
+ const Dict* dict = asDict(decodedValue);
+ if(!dict) {
throw DL_ABORT_EX(MSG_NULL_TRACKER_RESPONSE);
}
- const BDE& failure = dict[BtAnnounce::FAILURE_REASON];
- if(failure.isString()) {
+ const String* failure = asString(dict->get(BtAnnounce::FAILURE_REASON));
+ if(failure) {
throw DL_ABORT_EX
- (StringFormat(EX_TRACKER_FAILURE, failure.s().c_str()).str());
+ (StringFormat(EX_TRACKER_FAILURE, failure->s().c_str()).str());
}
- const BDE& warn = dict[BtAnnounce::WARNING_MESSAGE];
- if(warn.isString()) {
- _logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn.s().c_str());
+ const String* warn = asString(dict->get(BtAnnounce::WARNING_MESSAGE));
+ if(warn) {
+ _logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn->s().c_str());
}
- const BDE& tid = dict[BtAnnounce::TRACKER_ID];
- if(tid.isString()) {
- _trackerId = tid.s();
+ const String* tid = asString(dict->get(BtAnnounce::TRACKER_ID));
+ if(tid) {
+ _trackerId = tid->s();
if(_logger->debug()) {
_logger->debug("Tracker ID:%s", _trackerId.c_str());
}
}
- const BDE& ival = dict[BtAnnounce::INTERVAL];
- if(ival.isInteger() && ival.i() > 0) {
- _interval = ival.i();
+ const Integer* ival = asInteger(dict->get(BtAnnounce::INTERVAL));
+ if(ival && ival->i() > 0) {
+ _interval = ival->i();
if(_logger->debug()) {
_logger->debug("Interval:%d", _interval);
}
}
- const BDE& mival = dict[BtAnnounce::MIN_INTERVAL];
- if(mival.isInteger() && mival.i() > 0) {
- _minInterval = mival.i();
+ const Integer* mival = asInteger(dict->get(BtAnnounce::MIN_INTERVAL));
+ if(mival && mival->i() > 0) {
+ _minInterval = mival->i();
if(_logger->debug()) {
_logger->debug("Min interval:%d", _minInterval);
}
@@ -258,22 +257,22 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
// Use interval as a minInterval if minInterval is not supplied.
_minInterval = _interval;
}
- const BDE& comp = dict[BtAnnounce::COMPLETE];
- if(comp.isInteger()) {
- _complete = comp.i();
+ const Integer* comp = asInteger(dict->get(BtAnnounce::COMPLETE));
+ if(comp) {
+ _complete = comp->i();
if(_logger->debug()) {
_logger->debug("Complete:%d", _complete);
}
}
- const BDE& incomp = dict[BtAnnounce::INCOMPLETE];
- if(incomp.isInteger()) {
- _incomplete = incomp.i();
+ const Integer* incomp = asInteger(dict->get(BtAnnounce::INCOMPLETE));
+ if(incomp) {
+ _incomplete = incomp->i();
if(_logger->debug()) {
_logger->debug("Incomplete:%d", _incomplete);
}
}
- const BDE& peerData = dict[BtAnnounce::PEERS];
- if(peerData.isNone()) {
+ const SharedHandle<ValueBase>& peerData = dict->get(BtAnnounce::PEERS);
+ if(peerData.isNull()) {
_logger->info(MSG_NO_PEER_LIST_RECEIVED);
} else {
if(!_btRuntime->isHalt() && _btRuntime->lessThanMinPeers()) {
diff --git a/src/DefaultBtInteractive.cc b/src/DefaultBtInteractive.cc
index 6d21813b..8589ae63 100644
--- a/src/DefaultBtInteractive.cc
+++ b/src/DefaultBtInteractive.cc
@@ -202,9 +202,10 @@ void DefaultBtInteractive::addHandshakeExtendedMessageToQueue()
m->setClientVersion(CLIENT_ARIA2);
m->setTCPPort(_btRuntime->getListenPort());
m->setExtensions(_extensionMessageRegistry->getExtensions());
- const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT);
- if(attrs.containsKey(bittorrent::METADATA)) {
- m->setMetadataSize(attrs[bittorrent::METADATA_SIZE].i());
+ SharedHandle<TorrentAttribute> attrs =
+ bittorrent::getTorrentAttrs(_downloadContext);
+ if(!attrs->metadata.empty()) {
+ m->setMetadataSize(attrs->metadataSize);
}
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
_dispatcher->addMessageToQueue(msg);
diff --git a/src/DownloadContext.cc b/src/DownloadContext.cc
index 4a3dae52..30afcf18 100644
--- a/src/DownloadContext.cc
+++ b/src/DownloadContext.cc
@@ -40,6 +40,7 @@
#include "StringFormat.h"
#include "util.h"
#include "wallclock.h"
+#include "DlAbortEx.h"
namespace aria2 {
@@ -138,36 +139,33 @@ void DownloadContext::setFileFilter(IntSequence seq)
}
}
-void DownloadContext::ensureAttrs()
+void DownloadContext::setAttribute
+(const std::string& key, const SharedHandle<ContextAttribute>& value)
{
- if(_attrs.isNone()) {
- _attrs = BDE::dict();
+ std::map<std::string, SharedHandle<ContextAttribute> >::value_type p =
+ std::make_pair(key, value);
+ std::pair<std::map<std::string, SharedHandle<ContextAttribute> >::iterator,
+ bool> r = _attrs.insert(p);
+ if(!r.second) {
+ (*r.first).second = value;
}
}
-void DownloadContext::setAttribute(const std::string& key, const BDE& value)
+const SharedHandle<ContextAttribute>& DownloadContext::getAttribute
+(const std::string& key)
{
- ensureAttrs();
- _attrs[key] = value;
-}
-
-BDE& DownloadContext::getAttribute(const std::string& key)
-{
- ensureAttrs();
- if(_attrs.containsKey(key)) {
- return _attrs[key];
- } else {
+ std::map<std::string, SharedHandle<ContextAttribute> >::const_iterator itr =
+ _attrs.find(key);
+ if(itr == _attrs.end()) {
throw DL_ABORT_EX(StringFormat("No attribute named %s", key.c_str()).str());
+ } else {
+ return (*itr).second;
}
}
bool DownloadContext::hasAttribute(const std::string& key) const
{
- if(_attrs.isNone()) {
- return false;
- } else {
- return _attrs.containsKey(key);
- }
+ return _attrs.count(key) == 1;
}
void DownloadContext::releaseRuntimeResource()
diff --git a/src/DownloadContext.h b/src/DownloadContext.h
index 563a601d..e94efd93 100644
--- a/src/DownloadContext.h
+++ b/src/DownloadContext.h
@@ -45,9 +45,10 @@
#include "Signature.h"
#include "TimerA2.h"
#include "A2STR.h"
-#include "BDE.h"
+#include "ValueBase.h"
#include "IntSequence.h"
#include "FileEntry.h"
+#include "TorrentAttribute.h"
namespace aria2 {
@@ -76,15 +77,13 @@ private:
RequestGroup* _ownerRequestGroup;
- BDE _attrs;
+ std::map<std::string, SharedHandle<ContextAttribute> > _attrs;
Timer _downloadStartTime;
Timer _downloadStopTime;
SharedHandle<Signature> _signature;
-
- void ensureAttrs();
public:
DownloadContext();
@@ -224,9 +223,10 @@ public:
// this function.
void setFilePathWithIndex(size_t index, const std::string& path);
- void setAttribute(const std::string& key, const BDE& value);
+ void setAttribute
+ (const std::string& key, const SharedHandle<ContextAttribute>& value);
- BDE& getAttribute(const std::string& key);
+ const SharedHandle<ContextAttribute>& getAttribute(const std::string& key);
bool hasAttribute(const std::string& key) const;
diff --git a/src/HandshakeExtensionMessage.cc b/src/HandshakeExtensionMessage.cc
index 00763c65..20a3e2fb 100644
--- a/src/HandshakeExtensionMessage.cc
+++ b/src/HandshakeExtensionMessage.cc
@@ -110,21 +110,21 @@ void HandshakeExtensionMessage::doReceivedAction()
const std::map<std::string, uint8_t>::value_type& vt = *itr;
_peer->setExtension(vt.first, vt.second);
}
- BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
- if(!attrs.containsKey(bittorrent::METADATA) &&
- !_peer->getExtensionMessageID("ut_metadata")) {
+ SharedHandle<TorrentAttribute> attrs =
+ bittorrent::getTorrentAttrs(_dctx);
+ if(attrs->metadata.empty() && !_peer->getExtensionMessageID("ut_metadata")) {
// TODO In metadataGetMode, if peer don't support metadata
// transfer, should we drop connection? There is a possibility
// that peer can still tell us peers using PEX.
throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye.");
}
if(_metadataSize > 0) {
- if(attrs.containsKey(bittorrent::METADATA_SIZE)) {
- if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) {
+ if(attrs->metadataSize) {
+ if(_metadataSize != attrs->metadataSize) {
throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?");
}
} else {
- attrs[bittorrent::METADATA_SIZE] = _metadataSize;
+ attrs->metadataSize = _metadataSize;
_dctx->getFirstFileEntry()->setLength(_metadataSize);
_dctx->markTotalLengthIsKnown();
_dctx->getOwnerRequestGroup()->initPieceStorage();
@@ -133,7 +133,7 @@ void HandshakeExtensionMessage::doReceivedAction()
_dctx->getOwnerRequestGroup()->getPieceStorage();
pieceStorage->setEndGamePieceNum(0);
}
- } else if(!attrs.containsKey(bittorrent::METADATA)) {
+ } else if(attrs->metadata.empty()) {
throw DL_ABORT_EX("Peer didn't provide metadata_size."
" It seems that it doesn't have whole metadata.");
}
diff --git a/src/InitiateConnectionCommand.cc b/src/InitiateConnectionCommand.cc
index 8b57e18e..53454e56 100644
--- a/src/InitiateConnectionCommand.cc
+++ b/src/InitiateConnectionCommand.cc
@@ -52,6 +52,7 @@
#include "ServerStatMan.h"
#include "FileAllocationEntry.h"
#include "CheckIntegrityEntry.h"
+#include "RecoverableException.h"
namespace aria2 {
diff --git a/src/LpdReceiveMessageCommand.cc b/src/LpdReceiveMessageCommand.cc
index 7f106803..2208b41e 100644
--- a/src/LpdReceiveMessageCommand.cc
+++ b/src/LpdReceiveMessageCommand.cc
@@ -100,15 +100,12 @@ bool LpdReceiveMessageCommand::execute()
}
continue;
}
- const BDE& torrentAttrs = dctx->getAttribute(bittorrent::BITTORRENT);
- if(torrentAttrs.containsKey(bittorrent::PRIVATE)) {
- if(torrentAttrs[bittorrent::PRIVATE].i() == 1) {
- if(getLogger()->debug()) {
- getLogger()->debug
- ("Ignore LPD message because the torrent is private.");
- }
- continue;
+ if(bittorrent::getTorrentAttrs(dctx)->privateTorrent) {
+ if(getLogger()->debug()) {
+ getLogger()->debug
+ ("Ignore LPD message because the torrent is private.");
}
+ continue;
}
RequestGroup* group = dctx->getOwnerRequestGroup();
assert(group);
diff --git a/src/MSEHandshake.cc b/src/MSEHandshake.cc
index 704fc816..20706cd0 100644
--- a/src/MSEHandshake.cc
+++ b/src/MSEHandshake.cc
@@ -476,14 +476,13 @@ bool MSEHandshake::receiveReceiverHashAndPadCLength
downloadContexts.begin(), eoi = downloadContexts.end();
i != eoi; ++i) {
unsigned char md[20];
- const BDE& torrentAttrs = (*i)->getAttribute(bittorrent::BITTORRENT);
- createReq23Hash(md, torrentAttrs[bittorrent::INFO_HASH].uc());
+ const unsigned char* infohash = bittorrent::getInfoHash(*i);
+ createReq23Hash(md, infohash);
if(memcmp(md, rbufptr, sizeof(md)) == 0) {
if(_logger->debug()) {
_logger->debug("CUID#%s - info hash found: %s",
util::itos(_cuid).c_str(),
- util::toHex
- (torrentAttrs[bittorrent::INFO_HASH].s()).c_str());
+ util::toHex(infohash, INFO_HASH_LENGTH).c_str());
}
downloadContext = *i;
break;
diff --git a/src/Makefile.am b/src/Makefile.am
index 193838e5..485b604b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -202,7 +202,11 @@ SRCS = Socket.h\
MetadataInfo.cc MetadataInfo.h\
SessionSerializer.cc SessionSerializer.h\
Event.h\
- timespec.h
+ timespec.h\
+ ValueBase.cc ValueBase.h\
+ bencode2.cc bencode2.h\
+ ContextAttribute.h\
+ TorrentAttribute.h
if ENABLE_XML_RPC
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
diff --git a/src/Makefile.in b/src/Makefile.in
index 8764c069..8f5b23a3 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -437,7 +437,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
download_helper.cc download_helper.h MetadataInfo.cc \
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
- Event.h timespec.h XmlRpcRequestParserController.cc \
+ Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \
+ bencode2.h ContextAttribute.h TorrentAttribute.h \
+ XmlRpcRequestParserController.cc \
XmlRpcRequestParserController.h \
XmlRpcRequestParserStateMachine.cc \
XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \
@@ -873,7 +875,8 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
LongestSequencePieceSelector.$(OBJEXT) bitfield.$(OBJEXT) \
BDE.$(OBJEXT) CreateRequestCommand.$(OBJEXT) \
download_helper.$(OBJEXT) MetadataInfo.$(OBJEXT) \
- SessionSerializer.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
+ SessionSerializer.$(OBJEXT) ValueBase.$(OBJEXT) \
+ bencode2.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
$(am__objects_3) $(am__objects_4) $(am__objects_5) \
$(am__objects_6) $(am__objects_7) $(am__objects_8) \
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
@@ -1213,17 +1216,19 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
download_helper.cc download_helper.h MetadataInfo.cc \
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
- Event.h timespec.h $(am__append_1) $(am__append_2) \
- $(am__append_3) $(am__append_4) $(am__append_5) \
- $(am__append_6) $(am__append_7) $(am__append_8) \
- $(am__append_9) $(am__append_10) $(am__append_11) \
- $(am__append_12) $(am__append_13) $(am__append_14) \
- $(am__append_15) $(am__append_16) $(am__append_17) \
- $(am__append_18) $(am__append_19) $(am__append_20) \
- $(am__append_21) $(am__append_22) $(am__append_23) \
- $(am__append_24) $(am__append_25) $(am__append_26) \
- $(am__append_27) $(am__append_28) $(am__append_29) \
- $(am__append_30) $(am__append_31)
+ Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \
+ bencode2.h ContextAttribute.h TorrentAttribute.h \
+ $(am__append_1) $(am__append_2) $(am__append_3) \
+ $(am__append_4) $(am__append_5) $(am__append_6) \
+ $(am__append_7) $(am__append_8) $(am__append_9) \
+ $(am__append_10) $(am__append_11) $(am__append_12) \
+ $(am__append_13) $(am__append_14) $(am__append_15) \
+ $(am__append_16) $(am__append_17) $(am__append_18) \
+ $(am__append_19) $(am__append_20) $(am__append_21) \
+ $(am__append_22) $(am__append_23) $(am__append_24) \
+ $(am__append_25) $(am__append_26) $(am__append_27) \
+ $(am__append_28) $(am__append_29) $(am__append_30) \
+ $(am__append_31)
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -1612,6 +1617,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ValueBase.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2XmlRpcRequestProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcElements.Po@am__quote@
@@ -1626,6 +1632,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asctime_r.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode2.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfield.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_mingw.Po@am__quote@
diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc
index ffbe74f5..8fa666f6 100644
--- a/src/PeerInteractionCommand.cc
+++ b/src/PeerInteractionCommand.cc
@@ -102,11 +102,9 @@ PeerInteractionCommand::PeerInteractionCommand
setWriteCheckSocket(getSocket());
setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT));
}
-
- const BDE& torrentAttrs =
- _requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
-
- bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(_requestGroup->getDownloadContext());
+ bool metadataGetMode = torrentAttrs->metadata.empty();
SharedHandle<ExtensionMessageRegistry> exMsgRegistry
(new ExtensionMessageRegistry());
@@ -189,7 +187,7 @@ PeerInteractionCommand::PeerInteractionCommand
(getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL));
btInteractive->setRequestGroupMan(getDownloadEngine()->getRequestGroupMan());
btInteractive->setBtMessageFactory(factory);
- if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) &&
+ if((metadataGetMode || !torrentAttrs->privateTorrent) &&
!getPeer()->isLocalPeer()) {
if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) {
btInteractive->setUTPexEnabled(true);
diff --git a/src/PeerListProcessor.h b/src/PeerListProcessor.h
index 9aff5b88..6210fcf7 100644
--- a/src/PeerListProcessor.h
+++ b/src/PeerListProcessor.h
@@ -42,12 +42,71 @@
#include "a2netcompat.h"
#include "bencode.h"
#include "Peer.h"
+#include "ValueBase.h"
namespace aria2 {
class PeerListProcessor {
+private:
+ template<typename OutputIterator>
+ class PeerListValueBaseVisitor:public ValueBaseVisitor {
+ OutputIterator dest_;
+ public:
+ PeerListValueBaseVisitor(OutputIterator dest):dest_(dest) {}
+
+ virtual void visit(const String& peerData)
+ {
+ size_t length = peerData.s().size();
+ if(length%6 == 0) {
+ const char* base = peerData.s().data();
+ for(size_t i = 0; i < length; i += 6) {
+ struct in_addr in;
+ memcpy(&in.s_addr, base+i, sizeof(uint32_t));
+ std::string ipaddr = inet_ntoa(in);
+ uint16_t port_nworder;
+ memcpy(&port_nworder, base+i+4, sizeof(uint16_t));
+ uint16_t port = ntohs(port_nworder);
+ *dest_ = SharedHandle<Peer>(new Peer(ipaddr, port));
+ ++dest_;
+ }
+ }
+ }
+
+ virtual void visit(const Integer& v) {}
+
+ virtual void visit(const List& peerData)
+ {
+ for(List::ValueType::const_iterator itr = peerData.begin(),
+ eoi = peerData.end(); itr != eoi; ++itr) {
+ const Dict* peerDict = asDict(*itr);
+ if(!peerDict) {
+ continue;
+ }
+ static const std::string IP = "ip";
+ static const std::string PORT = "port";
+ const String* ip = asString(peerDict->get(IP));
+ const Integer* port = asInteger(peerDict->get(PORT));
+ if(!ip || !port || !(0 < port->i() && port->i() < 65536)) {
+ continue;
+ }
+ *dest_ = SharedHandle<Peer>(new Peer(ip->s(), port->i()));
+ ++dest_;
+ }
+ }
+
+ virtual void visit(const Dict& v) {}
+ };
public:
template<typename OutputIterator>
+ void extractPeer(const SharedHandle<ValueBase>& peerData, OutputIterator dest)
+ {
+ if(!peerData.isNull()) {
+ PeerListValueBaseVisitor<OutputIterator> visitor(dest);
+ peerData->accept(visitor);
+ }
+ }
+
+ template<typename OutputIterator>
void extractPeer(const BDE& peerData, OutputIterator dest)
{
if(peerData.isList()) {
diff --git a/src/ProtocolDetector.cc b/src/ProtocolDetector.cc
index 99c71161..c90cc1ac 100644
--- a/src/ProtocolDetector.cc
+++ b/src/ProtocolDetector.cc
@@ -41,6 +41,7 @@
#include "Request.h"
#include "File.h"
#include "util.h"
+#include "RecoverableException.h"
#ifdef ENABLE_BITTORRENT
# include "bittorrent_helper.h"
#endif // ENABLE_BITTORRENT
diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc
index 9d45b645..5774da48 100644
--- a/src/RequestGroup.cc
+++ b/src/RequestGroup.cc
@@ -202,16 +202,15 @@ void RequestGroup::createInitialCommand
#ifdef ENABLE_BITTORRENT
{
if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
- const BDE& torrentAttrs =
- _downloadContext->getAttribute(bittorrent::BITTORRENT);
- bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(_downloadContext);
+ bool metadataGetMode = torrentAttrs->metadata.empty();
if(_option->getAsBool(PREF_DRY_RUN)) {
throw DOWNLOAD_FAILURE_EXCEPTION
("Cancel BitTorrent download in dry-run context.");
}
SharedHandle<BtRegistry> btRegistry = e->getBtRegistry();
- if(!btRegistry->getDownloadContext
- (torrentAttrs[bittorrent::INFO_HASH].s()).isNull()) {
+ if(!btRegistry->getDownloadContext(torrentAttrs->infoHash).isNull()) {
// TODO If metadataGetMode == false and each FileEntry has
// URI, then go without BT.
throw DOWNLOAD_FAILURE_EXCEPTION
@@ -337,20 +336,14 @@ void RequestGroup::createInitialCommand
}
_progressInfoFile = progressInfoFile;
- if(torrentAttrs[bittorrent::PRIVATE].i() == 0 &&
- _option->getAsBool(PREF_ENABLE_DHT)) {
+ if(!torrentAttrs->privateTorrent && _option->getAsBool(PREF_ENABLE_DHT)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e);
e->addCommand(dhtCommands);
- if(!torrentAttrs[bittorrent::NODES].empty() && DHTSetup::initialized()) {
- std::vector<std::pair<std::string, uint16_t> > entryPoints;
- const BDE& nodes = torrentAttrs[bittorrent::NODES];
- for(BDE::List::const_iterator i = nodes.listBegin(),
- eoi = nodes.listEnd(); i != eoi; ++i) {
- std::pair<std::string, uint16_t> addr
- ((*i)[bittorrent::HOSTNAME].s(), (*i)[bittorrent::PORT].i());
- entryPoints.push_back(addr);
- }
+ const std::vector<std::pair<std::string, uint16_t> >& nodes =
+ torrentAttrs->nodes;
+ if(!nodes.empty() && DHTSetup::initialized()) {
+ std::vector<std::pair<std::string, uint16_t> > entryPoints(nodes);
DHTEntryPointNameResolveCommand* command =
new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints);
command->setTaskQueue(DHTRegistry::getData().taskQueue);
@@ -1094,8 +1087,9 @@ void RequestGroup::reportDownloadFinished()
TransferStat stat = calculateStat();
double shareRatio =
((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0;
- const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT);
- if(attrs.containsKey(bittorrent::METADATA)) {
+ SharedHandle<TorrentAttribute> attrs =
+ bittorrent::getTorrentAttrs(_downloadContext);
+ if(!attrs->metadata.empty()) {
_logger->notice(MSG_SHARE_RATIO_REPORT,
shareRatio,
util::abbrevSize(stat.getAllTimeUploadLength()).c_str(),
diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc
index b622c2ec..6adf2dda 100644
--- a/src/RequestGroupMan.cc
+++ b/src/RequestGroupMan.cc
@@ -70,6 +70,7 @@
#include "FileAllocationEntry.h"
#include "CheckIntegrityEntry.h"
#include "Segment.h"
+#include "DlAbortEx.h"
namespace aria2 {
diff --git a/src/TorrentAttribute.h b/src/TorrentAttribute.h
new file mode 100644
index 00000000..f977a4f2
--- /dev/null
+++ b/src/TorrentAttribute.h
@@ -0,0 +1,66 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef D_TORRENT_ATTRIBUTE_H
+#define D_TORRENT_ATTRIBUTE_H
+
+#include "ContextAttribute.h"
+
+#include <string>
+#include <vector>
+
+#include "a2time.h"
+
+struct TorrentAttribute:public ContextAttribute {
+ std::string name;
+ std::string mode;
+ std::vector<std::vector<std::string> > announceList;
+ std::vector<std::pair<std::string, uint16_t> > nodes;
+ // raw hash value 20 bytes.
+ std::string infoHash;
+ std::string metadata;
+ size_t metadataSize;
+ bool privateTorrent;
+ time_t creationDate;
+ std::string comment;
+ std::string createdBy;
+ std::vector<std::string> urlList;
+
+ TorrentAttribute():metadataSize(0),
+ privateTorrent(false),
+ creationDate(0) {}
+};
+
+#endif // D_TORRENT_ATTRIBUTE_H
+
diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc
index 682d0af1..09a29bf0 100644
--- a/src/TrackerWatcherCommand.cc
+++ b/src/TrackerWatcherCommand.cc
@@ -200,15 +200,15 @@ SharedHandle<RequestGroup> TrackerWatcherCommand::createAnnounce() {
static bool backupTrackerIsAvailable
(const SharedHandle<DownloadContext>& context)
{
- const BDE& announceList =
- context->getAttribute(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST];
- if(announceList.size() >= 2) {
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(context);
+ if(torrentAttrs->announceList.size() >= 2) {
return true;
}
- if(announceList.empty()) {
+ if(torrentAttrs->announceList.empty()) {
return false;
}
- if(announceList[0].size() >= 2) {
+ if(torrentAttrs->announceList[0].size() >= 2) {
return true;
} else {
return false;
diff --git a/src/UTMetadataDataExtensionMessage.cc b/src/UTMetadataDataExtensionMessage.cc
index 85b0efe0..2b97a1e2 100644
--- a/src/UTMetadataDataExtensionMessage.cc
+++ b/src/UTMetadataDataExtensionMessage.cc
@@ -85,9 +85,8 @@ void UTMetadataDataExtensionMessage::doReceivedAction()
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
MessageDigestContext::SHA1,
metadata.data(), metadata.size());
- const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
- if(std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]) ==
- attrs[bittorrent::INFO_HASH].s()){
+ if(memcmp(infoHash, bittorrent::getInfoHash(_dctx),
+ INFO_HASH_LENGTH) == 0) {
_logger->info("Got ut_metadata");
} else {
_logger->info("Got wrong ut_metadata");
diff --git a/src/UTMetadataPostDownloadHandler.cc b/src/UTMetadataPostDownloadHandler.cc
index 8f5ae4df..5127fd57 100644
--- a/src/UTMetadataPostDownloadHandler.cc
+++ b/src/UTMetadataPostDownloadHandler.cc
@@ -59,8 +59,8 @@ bool UTMetadataPostDownloadHandler::Criteria::match
const SharedHandle<DownloadContext>& dctx =
requestGroup->getDownloadContext();
if(dctx->hasAttribute(bittorrent::BITTORRENT)) {
- const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
- if(!attrs.containsKey(bittorrent::METADATA)) {
+ SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(dctx);
+ if(attrs->metadata.empty()) {
return true;
}
}
@@ -77,7 +77,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
(std::vector<SharedHandle<RequestGroup> >& groups, RequestGroup* requestGroup)
{
const SharedHandle<DownloadContext>& dctx =requestGroup->getDownloadContext();
- const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
+ SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(dctx);
std::string metadata =
util::toString(requestGroup->getPieceStorage()->getDiskAdaptor());
std::string torrent = bittorrent::metadata2Torrent(metadata, attrs);
@@ -85,7 +85,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
if(requestGroup->getOption()->getAsBool(PREF_BT_SAVE_METADATA)) {
std::string filename =
util::applyDir(requestGroup->getOption()->get(PREF_DIR),
- util::toHex(attrs[bittorrent::INFO_HASH].s())+".torrent");
+ util::toHex(attrs->infoHash)+".torrent");
if(util::saveAs(filename, torrent)) {
_logger->notice(MSG_METADATA_SAVED, filename.c_str());
} else {
diff --git a/src/UTMetadataRequestExtensionMessage.cc b/src/UTMetadataRequestExtensionMessage.cc
index e9e2e1f8..3bbaf4ac 100644
--- a/src/UTMetadataRequestExtensionMessage.cc
+++ b/src/UTMetadataRequestExtensionMessage.cc
@@ -70,27 +70,25 @@ std::string UTMetadataRequestExtensionMessage::toString() const
void UTMetadataRequestExtensionMessage::doReceivedAction()
{
- const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
+ SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(_dctx);
uint8_t id = _peer->getExtensionMessageID("ut_metadata");
- if(!attrs.containsKey(bittorrent::METADATA)) {
+ if(attrs->metadata.empty()) {
SharedHandle<UTMetadataRejectExtensionMessage> m
(new UTMetadataRejectExtensionMessage(id));
m->setIndex(getIndex());
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
_dispatcher->addMessageToQueue(msg);
- }else if(getIndex()*METADATA_PIECE_SIZE <
- (size_t)attrs[bittorrent::METADATA_SIZE].i()){
+ }else if(getIndex()*METADATA_PIECE_SIZE < attrs->metadataSize) {
SharedHandle<UTMetadataDataExtensionMessage> m
(new UTMetadataDataExtensionMessage(id));
m->setIndex(getIndex());
- m->setTotalSize(attrs[bittorrent::METADATA_SIZE].i());
- const BDE& metadata = attrs[bittorrent::METADATA];
+ m->setTotalSize(attrs->metadataSize);
std::string::const_iterator begin =
- metadata.s().begin()+getIndex()*METADATA_PIECE_SIZE;
+ attrs->metadata.begin()+getIndex()*METADATA_PIECE_SIZE;
std::string::const_iterator end =
- (getIndex()+1)*METADATA_PIECE_SIZE <= metadata.s().size()?
- metadata.s().begin()+(getIndex()+1)*METADATA_PIECE_SIZE:
- metadata.s().end();
+ (getIndex()+1)*METADATA_PIECE_SIZE <= attrs->metadata.size()?
+ attrs->metadata.begin()+(getIndex()+1)*METADATA_PIECE_SIZE:
+ attrs->metadata.end();
m->setData(std::string(begin, end));
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
_dispatcher->addMessageToQueue(msg);
diff --git a/src/ValueBase.cc b/src/ValueBase.cc
new file mode 100644
index 00000000..1e318f01
--- /dev/null
+++ b/src/ValueBase.cc
@@ -0,0 +1,347 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "ValueBase.h"
+
+namespace aria2 {
+
+const SharedHandle<ValueBase> ValueBase::none;
+
+String::String(const ValueType& string):str_(string) {}
+
+String::String(const char* cstring):str_(cstring) {}
+
+String::String(const char* data, size_t length):str_(&data[0], &data[length]) {}
+
+String::String(const unsigned char* data, size_t length):
+ str_(&data[0], &data[length]) {}
+
+String::String() {}
+
+const String::ValueType& String::s() const
+{
+ return str_;
+}
+
+const unsigned char* String::uc() const
+{
+ return reinterpret_cast<const unsigned char*>(str_.data());
+}
+
+SharedHandle<String> String::g(const ValueType& string)
+{
+ return SharedHandle<String>(new String(string));
+}
+
+void String::accept(ValueBaseVisitor& v) const
+{
+ v.visit(*this);
+}
+
+Integer::Integer(ValueType integer):integer_(integer) {}
+
+Integer::Integer():integer_(0) {}
+
+Integer::ValueType Integer::i() const
+{
+ return integer_;
+}
+
+SharedHandle<Integer> Integer::g(ValueType integer)
+{
+ return SharedHandle<Integer>(new Integer(integer));
+}
+
+void Integer::accept(ValueBaseVisitor& v) const
+{
+ v.visit(*this);
+}
+
+List::List() {}
+
+const SharedHandle<ValueBase>& List::get(size_t index) const
+{
+ return list_[index];
+}
+
+void List::append(const SharedHandle<ValueBase>& v)
+{
+ list_.push_back(v);
+}
+
+List& List::operator<<(const SharedHandle<ValueBase>& v)
+{
+ list_.push_back(v);
+ return *this;
+}
+
+const SharedHandle<ValueBase>& List::operator[](size_t index) const
+{
+ return list_[index];
+}
+
+List::ValueType::iterator List::begin()
+{
+ return list_.begin();
+}
+
+List::ValueType::iterator List::end()
+{
+ return list_.end();
+}
+
+List::ValueType::const_iterator List::begin() const
+{
+ return list_.begin();
+}
+
+List::ValueType::const_iterator List::end() const
+{
+ return list_.end();
+}
+
+size_t List::size() const
+{
+ return list_.size();
+}
+
+bool List::empty() const
+{
+ return list_.empty();
+}
+
+SharedHandle<List> List::g()
+{
+ return SharedHandle<List>(new List());
+}
+
+void List::accept(ValueBaseVisitor& v) const
+{
+ v.visit(*this);
+}
+
+Dict::Dict() {}
+
+void Dict::put(const std::string& key, const SharedHandle<ValueBase>& vlb)
+{
+ ValueType::value_type p = std::make_pair(key, vlb);
+ std::pair<ValueType::iterator, bool> r = dict_.insert(p);
+ if(!r.second) {
+ (*r.first).second = vlb;
+ }
+}
+
+void Dict::put(const std::string& key, const String::ValueType& string)
+{
+ put(key, String::g(string));
+}
+
+const SharedHandle<ValueBase>& Dict::get(const std::string& key) const
+{
+ ValueType::const_iterator itr = dict_.find(key);
+ if(itr == dict_.end()) {
+ return ValueBase::none;
+ } else {
+ return (*itr).second;
+ }
+}
+
+SharedHandle<ValueBase>& Dict::operator[](const std::string& key)
+{
+ return dict_[key];
+}
+
+const SharedHandle<ValueBase>& Dict::operator[](const std::string& key) const
+{
+ return get(key);
+}
+
+bool Dict::containsKey(const std::string& key) const
+{
+ return dict_.count(key) == 1;
+}
+
+void Dict::removeKey(const std::string& key)
+{
+ dict_.erase(key);
+}
+
+Dict::ValueType::iterator Dict::begin()
+{
+ return dict_.begin();
+}
+
+Dict::ValueType::iterator Dict::end()
+{
+ return dict_.end();
+}
+
+Dict::ValueType::const_iterator Dict::begin() const
+{
+ return dict_.begin();
+}
+
+Dict::ValueType::const_iterator Dict::end() const
+{
+ return dict_.end();
+}
+
+size_t Dict::size() const
+{
+ return dict_.size();
+}
+
+bool Dict::empty() const
+{
+ return dict_.empty();
+}
+
+SharedHandle<Dict> Dict::g()
+{
+ return SharedHandle<Dict>(new Dict());
+}
+void Dict::accept(ValueBaseVisitor& v) const
+{
+ v.visit(*this);
+}
+
+const String* asString(const ValueBase* v)
+{
+ if(v) {
+ return downcast<String, Integer, List, Dict>(v);
+ } else {
+ return 0;
+ }
+}
+
+String* asString(ValueBase* v)
+{
+ if(v) {
+ return const_cast<String*>(downcast<String, Integer, List, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+String* asString(const SharedHandle<ValueBase>& v)
+{
+ if(v.get()) {
+ return const_cast<String*>(downcast<String, Integer, List, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+const Integer* asInteger(const ValueBase* v)
+{
+ if(v) {
+ return downcast<Integer, String, List, Dict>(v);
+ } else {
+ return 0;
+ }
+}
+
+Integer* asInteger(ValueBase* v)
+{
+ if(v) {
+ return const_cast<Integer*>(downcast<Integer, String, List, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+Integer* asInteger(const SharedHandle<ValueBase>& v)
+{
+ if(v.get()) {
+ return const_cast<Integer*>(downcast<Integer, String, List, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+const List* asList(const ValueBase* v)
+{
+ if(v) {
+ return downcast<List, String, Integer, Dict>(v);
+ } else {
+ return 0;
+ }
+}
+
+List* asList(ValueBase* v)
+{
+ if(v) {
+ return const_cast<List*>(downcast<List, String, Integer, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+List* asList(const SharedHandle<ValueBase>& v)
+{
+ if(v.get()) {
+ return const_cast<List*>(downcast<List, String, Integer, Dict>(v));
+ } else {
+ return 0;
+ }
+}
+
+const Dict* asDict(const ValueBase* v)
+{
+ if(v) {
+ return downcast<Dict, String, Integer, List>(v);
+ } else {
+ return 0;
+ }
+}
+
+Dict* asDict(ValueBase* v)
+{
+ if(v) {
+ return const_cast<Dict*>(downcast<Dict, String, Integer, List>(v));
+ } else {
+ return 0;
+ }
+}
+
+Dict* asDict(const SharedHandle<ValueBase>& v)
+{
+ if(v.get()) {
+ return const_cast<Dict*>(downcast<Dict, String, Integer, List>(v));
+ } else {
+ return 0;
+ }
+}
+
+} // namespace aria2
diff --git a/src/ValueBase.h b/src/ValueBase.h
new file mode 100644
index 00000000..9dbbcf51
--- /dev/null
+++ b/src/ValueBase.h
@@ -0,0 +1,288 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef D_VALUE_BASE_H
+#define D_VALUE_BASE_H
+
+#include "common.h"
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "SharedHandle.h"
+
+namespace aria2 {
+
+class ValueBaseVisitor;
+
+class ValueBase {
+public:
+ virtual ~ValueBase() {}
+
+ virtual void accept(ValueBaseVisitor& visitor) const = 0;
+
+ static const SharedHandle<ValueBase> none;
+};
+
+class String;
+class Integer;
+class List;
+class Dict;
+
+class ValueBaseVisitor {
+public:
+ virtual ~ValueBaseVisitor() {}
+
+ virtual void visit(const String& string) = 0;
+
+ virtual void visit(const Integer& integer) = 0;
+
+ virtual void visit(const List& list) = 0;
+
+ virtual void visit(const Dict& dict) = 0;
+};
+
+class String:public ValueBase {
+public:
+ typedef std::string ValueType;
+
+ String(const ValueType& string);
+
+ explicit String(const char* cstring);
+
+ String(const char* data, size_t length);
+
+ String(const unsigned char* data, size_t length);
+
+ String();
+
+ const ValueType& s() const;
+
+ // Returns std::string.data() casted to unsigned char*.
+ // Use s().size() to get length.
+ const unsigned char* uc() const;
+
+ static SharedHandle<String> g(const ValueType& string);
+
+ virtual void accept(ValueBaseVisitor& visitor) const;
+private:
+ ValueType str_;
+};
+
+class Integer:public ValueBase {
+public:
+ typedef int64_t ValueType;
+
+ Integer(ValueType integer);
+
+ Integer();
+
+ // Returns Integer.
+ ValueType i() const;
+
+ static SharedHandle<Integer> g(ValueType integer);
+
+ virtual void accept(ValueBaseVisitor& visitor) const;
+private:
+ ValueType integer_;
+};
+
+class List:public ValueBase {
+public:
+ typedef std::vector<SharedHandle<ValueBase> > ValueType;
+
+ List();
+
+ // Appends given v to list.
+ void append(const SharedHandle<ValueBase>& v);
+
+ // Alias for append()
+ List& operator<<(const SharedHandle<ValueBase>& v);
+
+ // Returns the object at given index.
+ const SharedHandle<ValueBase>& get(size_t index) const;
+
+ // Returns the const reference of the object at the given index.
+ const SharedHandle<ValueBase>& operator[](size_t index) const;
+
+ // Returns a read/write iterator that points to the first object in
+ // list.
+ ValueType::iterator begin();
+
+ // Returns a read/write iterator that points to the one past the
+ // last object in list.
+ ValueType::iterator end();
+
+ // Returns a read/write read-only iterator that points to the first
+ // object in list.
+ ValueType::const_iterator begin() const;
+
+ // Returns a read/write read-only iterator that points to the one
+ // past the last object in list.
+ ValueType::const_iterator end() const;
+
+ // Returns size of list.
+ size_t size() const;
+
+ // Returns true if size of list is 0.
+ bool empty() const;
+
+ static SharedHandle<List> g();
+
+ virtual void accept(ValueBaseVisitor& visitor) const;
+private:
+ ValueType list_;
+};
+
+class Dict:public ValueBase {
+public:
+ typedef std::map<std::string, SharedHandle<ValueBase> > ValueType;
+
+ Dict();
+
+ void put(const std::string& key, const SharedHandle<ValueBase>& vlb);
+
+ // Putting string is so common that we provide shortcut function.
+ void put(const std::string& key, const String::ValueType& string);
+
+ const SharedHandle<ValueBase>& get(const std::string& key) const;
+
+ // Returns the reference to object associated with given key. If
+ // the key is not found, new pair with that key is created using
+ // default values, which is then returned. In other words, this is
+ // the same behavior of std::map's operator[].
+ SharedHandle<ValueBase>& operator[](const std::string& key);
+
+ // Returns the const reference to ojbect associated with given key.
+ // If the key is not found, ValueBase::none is returned.
+ const SharedHandle<ValueBase>& operator[](const std::string& key) const;
+
+ // Returns true if the given key is found in dict.
+ bool containsKey(const std::string& key) const;
+
+ // Removes specified key from dict.
+ void removeKey(const std::string& key);
+
+ // Returns a read/write iterator that points to the first pair in
+ // the dict.
+ ValueType::iterator begin();
+
+ // Returns a read/write read-only iterator that points to one past
+ // the last pair in the dict.
+ ValueType::iterator end();
+
+ // Returns a read/write read-only iterator that points to the first
+ // pair in the dict.
+ ValueType::const_iterator begin() const;
+
+ // Returns a read/write read-only iterator that points to one past
+ // the last pair in the dict.
+ ValueType::const_iterator end() const;
+
+ // Returns size of Dict.
+ size_t size() const;
+
+ // Returns true if size of Dict is 0.
+ bool empty() const;
+
+ static SharedHandle<Dict> g();
+
+ virtual void accept(ValueBaseVisitor& visitor) const;
+private:
+ ValueType dict_;
+};
+
+template<typename T, typename T1, typename T2, typename T3>
+class DowncastValueBaseVisitor:public ValueBaseVisitor {
+private:
+ const T* result_;
+public:
+ DowncastValueBaseVisitor():result_(0) {}
+
+ virtual void visit(const T& t)
+ {
+ result_ = &t;
+ }
+
+ virtual void visit(const T1& t1) {}
+ virtual void visit(const T2& t2) {}
+ virtual void visit(const T3& t3) {}
+
+ const T* getResult() const
+ {
+ return result_;
+ }
+
+ void setResult(const T* r)
+ {
+ result_ = r;
+ }
+};
+
+template<typename T, typename T1, typename T2, typename T3, typename VPtr>
+const T* downcast(const VPtr& v)
+{
+ DowncastValueBaseVisitor<T, T1, T2, T3> visitor;
+ v->accept(visitor);
+ return visitor.getResult();
+}
+
+const String* asString(const ValueBase* v);
+
+String* asString(ValueBase* v);
+
+String* asString(const SharedHandle<ValueBase>& v);
+
+const Integer* asInteger(const ValueBase* v);
+
+Integer* asInteger(ValueBase* v);
+
+Integer* asInteger(const SharedHandle<ValueBase>& v);
+
+const List* asList(const ValueBase* v);
+
+List* asList(ValueBase* v);
+
+List* asList(const SharedHandle<ValueBase>& v);
+
+const Dict* asDict(const ValueBase* v);
+
+Dict* asDict(ValueBase* v);
+
+Dict* asDict(const SharedHandle<ValueBase>& v);
+
+} // namespace aria2
+
+#endif // D_VALUE_BASE_H
diff --git a/src/XmlRpcMethodImpl.cc b/src/XmlRpcMethodImpl.cc
index 6e447f13..f1db44e4 100644
--- a/src/XmlRpcMethodImpl.cc
+++ b/src/XmlRpcMethodImpl.cc
@@ -563,44 +563,43 @@ void gatherProgressCommon
}
#ifdef ENABLE_BITTORRENT
-void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs)
+void gatherBitTorrentMetadata
+(BDE& btDict, const SharedHandle<TorrentAttribute>& torrentAttrs)
{
- if(torrentAttrs.containsKey(bittorrent::COMMENT)) {
- btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT];
+ if(!torrentAttrs->comment.empty()) {
+ btDict[KEY_COMMENT] = torrentAttrs->comment;
}
- if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) {
- btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE];
+ if(torrentAttrs->creationDate) {
+ btDict[KEY_CREATION_DATE] = torrentAttrs->creationDate;
}
- if(torrentAttrs.containsKey(bittorrent::MODE)) {
- btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE];
+ if(!torrentAttrs->mode.empty()) {
+ btDict[KEY_MODE] = torrentAttrs->mode;
}
- // Copy announceList to avoid modification on entyDict to be
- // affected original announceList.
- // TODO Would it be good to add copy() method in BDE?
- const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST];
BDE destAnnounceList = BDE::list();
- for(BDE::List::const_iterator l = announceList.listBegin(),
- eoi = announceList.listEnd(); l != eoi; ++l) {
+ for(std::vector<std::vector<std::string> >::const_iterator l =
+ torrentAttrs->announceList.begin(),
+ eoi = torrentAttrs->announceList.end(); l != eoi; ++l) {
BDE destAnnounceTier = BDE::list();
- for(BDE::List::const_iterator t = (*l).listBegin(),
- eoi2 = (*l).listEnd(); t != eoi2; ++t) {
- destAnnounceTier << (*t);
+ for(std::vector<std::string>::const_iterator t = (*l).begin(),
+ eoi2 = (*l).end(); t != eoi2; ++t) {
+ destAnnounceTier << *t;
}
destAnnounceList << destAnnounceTier;
}
btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
- if(torrentAttrs.containsKey(bittorrent::METADATA)) {
+ if(!torrentAttrs->metadata.empty()) {
BDE infoDict = BDE::dict();
- infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME];
+ infoDict[KEY_NAME] = torrentAttrs->name;
btDict[KEY_INFO] = infoDict;
}
}
static void gatherProgressBitTorrent
-(BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
+(BDE& entryDict,
+ const SharedHandle<TorrentAttribute>& torrentAttrs,
+ const BtObject& btObject)
{
- const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
- entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
+ entryDict[KEY_INFO_HASH] = util::toHex(torrentAttrs->infoHash);
BDE btDict = BDE::dict();
gatherBitTorrentMetadata(btDict, torrentAttrs);
entryDict[KEY_BITTORRENT] = btDict;
@@ -651,8 +650,8 @@ static void gatherProgress
gatherProgressCommon(entryDict, group);
#ifdef ENABLE_BITTORRENT
if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
- const BDE& torrentAttrs =
- group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(group->getDownloadContext());
BtObject btObject = e->getBtRegistry()->get(group->getGID());
gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
}
diff --git a/src/XmlRpcMethodImpl.h b/src/XmlRpcMethodImpl.h
index 66e81792..0b7abbae 100644
--- a/src/XmlRpcMethodImpl.h
+++ b/src/XmlRpcMethodImpl.h
@@ -43,6 +43,8 @@
#include "BDE.h"
#include "XmlRpcRequest.h"
+#include "ValueBase.h"
+#include "TorrentAttribute.h"
namespace aria2 {
@@ -500,9 +502,9 @@ void gatherProgressCommon
(BDE& entryDict, const SharedHandle<RequestGroup>& group);
#ifdef ENABLE_BITTORRENT
-// Helper function to store BitTorrent metadata from torrentAttrs in
-// btDict. btDict must be an BDE::Dict.
-void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs);
+// Helper function to store BitTorrent metadata from torrentAttrs.
+void gatherBitTorrentMetadata
+(BDE& btDict, const SharedHandle<TorrentAttribute>& torrentAttrs);
#endif // ENABLE_BITTORRENT
} // namespace xmlrpc
diff --git a/src/bencode2.cc b/src/bencode2.cc
new file mode 100644
index 00000000..6e2d3b8c
--- /dev/null
+++ b/src/bencode2.cc
@@ -0,0 +1,263 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "bencode2.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "StringFormat.h"
+#include "DlAbortEx.h"
+
+namespace aria2 {
+
+namespace bencode2 {
+
+static SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth);
+
+static void checkdelim(std::istream& ss, const char delim = ':')
+{
+ char d;
+ if(!(ss.get(d) && d == delim)) {
+ throw DL_ABORT_EX
+ (StringFormat("Bencode decoding failed: Delimiter '%c' not found.",
+ delim).str());
+ }
+}
+
+static std::string decoderawstring(std::istream& ss)
+{
+ int length;
+ ss >> length;
+ if(!ss || length < 0) {
+ throw DL_ABORT_EX("Bencode decoding failed:"
+ " A positive integer expected but none found.");
+ }
+ // TODO check length, it must be less than or equal to INT_MAX
+ checkdelim(ss);
+ char* buf = new char[length];
+ ss.read(buf, length);
+ std::string str(&buf[0], &buf[length]);
+ delete [] buf;
+ if(ss.gcount() != static_cast<int>(length)) {
+ throw DL_ABORT_EX
+ (StringFormat("Bencode decoding failed:"
+ " Expected %lu bytes of data, but only %d read.",
+ static_cast<unsigned long>(length), ss.gcount()).str());
+ }
+ return str;
+}
+
+static SharedHandle<ValueBase> decodestring(std::istream& ss)
+{
+ return String::g(decoderawstring(ss));
+}
+
+static SharedHandle<ValueBase> decodeinteger(std::istream& ss)
+{
+ Integer::ValueType iv;
+ ss >> iv;
+ if(!ss) {
+ throw DL_ABORT_EX("Bencode decoding failed:"
+ " Integer expected but none found");
+ }
+ checkdelim(ss, 'e');
+ return Integer::g(iv);
+}
+
+static SharedHandle<ValueBase> decodedict(std::istream& ss, size_t depth)
+{
+ SharedHandle<Dict> dict = Dict::g();
+ char c;
+ while(ss.get(c)) {
+ if(c == 'e') {
+ return dict;
+ } else {
+ ss.unget();
+ std::string key = decoderawstring(ss);
+ dict->put(key, decodeiter(ss, depth));
+ }
+ }
+ throw DL_ABORT_EX("Bencode decoding failed:"
+ " Unexpected EOF in dict context. 'e' expected.");
+}
+
+static SharedHandle<ValueBase> decodelist(std::istream& ss, size_t depth)
+{
+ SharedHandle<List> list = List::g();
+ char c;
+ while(ss.get(c)) {
+ if(c == 'e') {
+ return list;
+ } else {
+ ss.unget();
+ list->append(decodeiter(ss, depth));
+ }
+ }
+ throw DL_ABORT_EX("Bencode decoding failed:"
+ " Unexpected EOF in list context. 'e' expected.");
+}
+
+static void checkDepth(size_t depth)
+{
+ if(depth >= MAX_STRUCTURE_DEPTH) {
+ throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep.");
+ }
+}
+
+static SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth)
+{
+ checkDepth(depth);
+ char c;
+ if(!ss.get(c)) {
+ throw DL_ABORT_EX("Bencode decoding failed:"
+ " Unexpected EOF in term context."
+ " 'd', 'l', 'i' or digit is expected.");
+ }
+ if(c == 'd') {
+ return decodedict(ss, depth+1);
+ } else if(c == 'l') {
+ return decodelist(ss, depth+1);
+ } else if(c == 'i') {
+ return decodeinteger(ss);
+ } else {
+ ss.unget();
+ return decodestring(ss);
+ }
+}
+
+SharedHandle<ValueBase> decode(std::istream& in)
+{
+ return decodeiter(in, 0);
+}
+
+SharedHandle<ValueBase> decode(const std::string& s)
+{
+ size_t end;
+ return decode(s, end);
+}
+
+SharedHandle<ValueBase> decode(const std::string& s, size_t& end)
+{
+ if(s.empty()) {
+ return SharedHandle<ValueBase>();
+ }
+ std::istringstream ss(s);
+
+ SharedHandle<ValueBase> vlb = decodeiter(ss, 0);
+ end = ss.tellg();
+ return vlb;
+}
+
+SharedHandle<ValueBase> decode(const unsigned char* data, size_t length)
+{
+ return decode(std::string(&data[0], &data[length]));
+}
+
+SharedHandle<ValueBase> decode(const unsigned char* data, size_t length, size_t& end)
+{
+ return decode(std::string(&data[0], &data[length]), end);
+}
+
+SharedHandle<ValueBase> decodeFromFile(const std::string& filename)
+{
+ std::ifstream f(filename.c_str(), std::ios::binary);
+ if(f) {
+ return decode(f);
+ } else {
+ throw DL_ABORT_EX
+ (StringFormat("Bencode decoding failed:"
+ " Cannot open file '%s'.", filename.c_str()).str());
+ }
+}
+
+std::string encode(const ValueBase* vlb)
+{
+ class BencodeValueBaseVisitor:public ValueBaseVisitor {
+ private:
+ std::ostringstream out_;
+ public:
+ virtual void visit(const String& string)
+ {
+ const std::string& s = string.s();
+ out_ << s.size() << ":";
+ out_.write(s.data(), s.size());
+ }
+
+ virtual void visit(const Integer& integer)
+ {
+ out_ << "i" << integer.i() << "e";
+ }
+
+ virtual void visit(const List& list)
+ {
+ out_ << "l";
+ for(List::ValueType::const_iterator i = list.begin(), eoi = list.end();
+ i != eoi; ++i){
+ (*i)->accept(*this);
+ }
+ out_ << "e";
+ }
+
+ virtual void visit(const Dict& dict)
+ {
+ out_ << "d";
+ for(Dict::ValueType::const_iterator i = dict.begin(), eoi = dict.end();
+ i != eoi; ++i){
+ const std::string& key = (*i).first;
+ out_ << key.size() << ":";
+ out_.write(key.data(), key.size());
+ (*i).second->accept(*this);
+ }
+ out_ << "e";
+ }
+
+ std::string getResult() const
+ {
+ return out_.str();
+ }
+ };
+ BencodeValueBaseVisitor visitor;
+ vlb->accept(visitor);
+ return visitor.getResult();
+}
+
+std::string encode(const SharedHandle<ValueBase>& vlb)
+{
+ return encode(vlb.get());
+}
+
+} // namespace bencode2
+
+} // namespace aria2
diff --git a/src/bencode2.h b/src/bencode2.h
new file mode 100644
index 00000000..27f2896b
--- /dev/null
+++ b/src/bencode2.h
@@ -0,0 +1,75 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ *
+ * 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 the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * 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) with this exception, 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. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BENCODE2_H_
+#define _D_BENCODE2_H_
+
+#include "common.h"
+
+#include <string>
+#include <iosfwd>
+
+#include "ValueBase.h"
+
+namespace aria2 {
+
+namespace bencode2 {
+
+const size_t MAX_STRUCTURE_DEPTH = 100;
+
+SharedHandle<ValueBase> decode(std::istream& in);
+
+// Decode the data in s.
+SharedHandle<ValueBase> decode(const std::string& s);
+
+// Decode the data in s. After decode is done successfully, return the
+// bencoded string length in end.
+SharedHandle<ValueBase> decode(const std::string& s, size_t& end);
+
+SharedHandle<ValueBase> decode(const unsigned char* data, size_t length);
+
+SharedHandle<ValueBase> decode
+(const unsigned char* data, size_t length, size_t& end);
+
+SharedHandle<ValueBase> decodeFromFile(const std::string& filename);
+
+std::string encode(const ValueBase* vlb);
+
+std::string encode(const SharedHandle<ValueBase>& vlb);
+
+} // namespace bencode2
+
+} // namespace aria2
+
+#endif // _D_BENCODE2_H_
diff --git a/src/bittorrent_helper.cc b/src/bittorrent_helper.cc
index 42b1c4a8..cbac20c7 100644
--- a/src/bittorrent_helper.cc
+++ b/src/bittorrent_helper.cc
@@ -54,6 +54,9 @@
#include "bitfield.h"
#include "base32.h"
#include "magnet.h"
+#include "ValueBase.h"
+#include "bencode2.h"
+#include "TorrentAttribute.h"
namespace aria2 {
@@ -147,23 +150,44 @@ static void extractPieceHash(const SharedHandle<DownloadContext>& ctx,
}
static void extractUrlList
-(BDE& torrent, std::vector<std::string>& uris, const BDE& bde)
+(const SharedHandle<TorrentAttribute>& torrent, std::vector<std::string>& uris,
+ const ValueBase* v)
{
- if(bde.isList()) {
- for(BDE::List::const_iterator itr = bde.listBegin(), eoi = bde.listEnd();
- itr != eoi; ++itr) {
- if((*itr).isString()) {
- uris.push_back((*itr).s());
+ class UrlListVisitor:public ValueBaseVisitor {
+ private:
+ std::vector<std::string>& uris_;
+ const SharedHandle<TorrentAttribute>& torrent_;
+ public:
+ UrlListVisitor
+ (std::vector<std::string>& uris,
+ const SharedHandle<TorrentAttribute>& torrent):
+ uris_(uris), torrent_(torrent) {}
+
+ virtual void visit(const String& v)
+ {
+ uris_.push_back(v.s());
+ torrent_->urlList.push_back(v.s());
+ }
+
+ virtual void visit(const Integer& v) {}
+
+ virtual void visit(const List& v)
+ {
+ for(List::ValueType::const_iterator itr = v.begin(), eoi = v.end();
+ itr != eoi; ++itr) {
+ const String* uri = asString(*itr);
+ if(uri) {
+ uris_.push_back(uri->s());
+ torrent_->urlList.push_back(uri->s());
+ }
}
}
- torrent[URL_LIST] = bde;
- } else if(bde.isString()) {
- uris.push_back(bde.s());
- BDE urlList = BDE::list();
- urlList << bde;
- torrent[URL_LIST] = urlList;
- } else {
- torrent[URL_LIST] = BDE::list();
+ virtual void visit(const Dict& v) {}
+ };
+
+ if(v) {
+ UrlListVisitor visitor(uris, torrent);
+ v->accept(visitor);
}
}
@@ -184,8 +208,8 @@ static OutputIterator createUri
static void extractFileEntries
(const SharedHandle<DownloadContext>& ctx,
- BDE& torrent,
- const BDE& infoDict,
+ const SharedHandle<TorrentAttribute>& torrent,
+ const Dict* infoDict,
const std::string& defaultName,
const std::string& overrideName,
const std::vector<std::string>& urlList)
@@ -193,62 +217,71 @@ static void extractFileEntries
std::string name;
if(overrideName.empty()) {
std::string nameKey;
- if(infoDict.containsKey(C_NAME_UTF8)) {
+ if(infoDict->containsKey(C_NAME_UTF8)) {
nameKey = C_NAME_UTF8;
} else {
nameKey = C_NAME;
}
- const BDE& nameData = infoDict[nameKey];
- if(nameData.isString()) {
- if(util::detectDirTraversal(nameData.s())) {
+ const String* nameData = asString(infoDict->get(nameKey));
+ if(nameData) {
+ if(util::detectDirTraversal(nameData->s())) {
throw DL_ABORT_EX
- (StringFormat(MSG_DIR_TRAVERSAL_DETECTED,nameData.s().c_str()).str());
+ (StringFormat
+ (MSG_DIR_TRAVERSAL_DETECTED,nameData->s().c_str()).str());
}
- name = nameData.s();
+ name = nameData->s();
} else {
name = strconcat(File(defaultName).getBasename(), ".file");
}
} else {
name = overrideName;
}
- torrent[NAME] = name;
-
- const BDE& filesList = infoDict[C_FILES];
+ torrent->name = name;
std::vector<SharedHandle<FileEntry> > fileEntries;
- if(filesList.isList()) {
- fileEntries.reserve(filesList.size());
+ const List* filesList = asList(infoDict->get(C_FILES));
+ if(filesList) {
+ fileEntries.reserve(filesList->size());
uint64_t length = 0;
off_t offset = 0;
// multi-file mode
- torrent[MODE] = MULTI;
- for(BDE::List::const_iterator itr = filesList.listBegin(),
- eoi = filesList.listEnd(); itr != eoi; ++itr) {
- const BDE& fileDict = *itr;
- if(!fileDict.isDict()) {
+ torrent->mode = MULTI;
+ for(List::ValueType::const_iterator itr = filesList->begin(),
+ eoi = filesList->end(); itr != eoi; ++itr) {
+ const Dict* fileDict = asDict(*itr);
+ if(!fileDict) {
continue;
}
- const BDE& fileLengthData = fileDict[C_LENGTH];
- if(!fileLengthData.isInteger()) {
+ const Integer* fileLengthData = asInteger(fileDict->get(C_LENGTH));
+ if(!fileLengthData) {
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
C_LENGTH.c_str()).str());
}
- length += fileLengthData.i();
+ length += fileLengthData->i();
std::string pathKey;
- if(fileDict.containsKey(C_PATH_UTF8)) {
+ if(fileDict->containsKey(C_PATH_UTF8)) {
pathKey = C_PATH_UTF8;
} else {
pathKey = C_PATH;
}
- const BDE& pathList = fileDict[pathKey];
- if(!pathList.isList() || pathList.empty()) {
+ const List* pathList = asList(fileDict->get(pathKey));
+ if(!pathList || pathList->empty()) {
throw DL_ABORT_EX("Path is empty.");
}
- std::vector<std::string> pathelem(pathList.size()+1);
+ std::vector<std::string> pathelem(pathList->size()+1);
pathelem[0] = name;
- std::transform(pathList.listBegin(), pathList.listEnd(),
- pathelem.begin()+1, std::mem_fun_ref(&BDE::s));
+ std::vector<std::string>::iterator pathelemOutItr = pathelem.begin();
+ ++pathelemOutItr;
+ for(List::ValueType::const_iterator itr = pathList->begin(),
+ eoi = pathList->end(); itr != eoi; ++itr) {
+ const String* elem = asString(*itr);
+ if(elem) {
+ (*pathelemOutItr++) = elem->s();
+ } else {
+ throw DL_ABORT_EX("Path element is not string.");
+ }
+ }
std::string path = strjoin(pathelem.begin(), pathelem.end(), '/');
if(util::detectDirTraversal(path)) {
throw DL_ABORT_EX
@@ -262,7 +295,7 @@ static void extractFileEntries
createUri(urlList.begin(), urlList.end(),std::back_inserter(uris),pePath);
SharedHandle<FileEntry> fileEntry
(new FileEntry(util::applyDir(ctx->getDir(), util::escapePath(path)),
- fileLengthData.i(),
+ fileLengthData->i(),
offset, uris));
fileEntry->setOriginalName(path);
fileEntries.push_back(fileEntry);
@@ -270,13 +303,13 @@ static void extractFileEntries
}
} else {
// single-file mode;
- torrent[MODE] = SINGLE;
- const BDE& lengthData = infoDict[C_LENGTH];
- if(!lengthData.isInteger()) {
+ torrent->mode = SINGLE;
+ const Integer* lengthData = asInteger(infoDict->get(C_LENGTH));
+ if(!lengthData) {
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
C_LENGTH.c_str()).str());
}
- uint64_t totalLength = lengthData.i();
+ uint64_t totalLength = lengthData->i();
// For each uri in urlList, if it ends with '/', then
// concatenate name to it. Specification just says so.
@@ -298,98 +331,103 @@ static void extractFileEntries
fileEntries.push_back(fileEntry);
}
ctx->setFileEntries(fileEntries.begin(), fileEntries.end());
- if(torrent[MODE].s() == MULTI) {
+ if(torrent->mode == MULTI) {
ctx->setBasePath(util::applyDir(ctx->getDir(), name));
}
}
-static void extractAnnounce(BDE& torrent, const BDE& rootDict)
+static void extractAnnounce
+(const SharedHandle<TorrentAttribute>& torrent, const Dict* rootDict)
{
- const BDE& announceList = rootDict[C_ANNOUNCE_LIST];
- if(announceList.isList()) {
- torrent[ANNOUNCE_LIST] = announceList;
- BDE& tiers = torrent[ANNOUNCE_LIST];
- for(BDE::List::iterator tieriter = tiers.listBegin(),
- eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) {
- for(BDE::List::iterator uriiter = (*tieriter).listBegin(),
- eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) {
- if((*uriiter).isString()) {
- *uriiter = util::trim((*uriiter).s());
+ const List* announceList = asList(rootDict->get(C_ANNOUNCE_LIST));
+ if(announceList) {
+ for(List::ValueType::const_iterator tierIter = announceList->begin(),
+ eoi = announceList->end(); tierIter != eoi; ++tierIter) {
+ const List* tier = asList(*tierIter);
+ if(!tier) {
+ continue;
+ }
+ std::vector<std::string> ntier;
+ for(List::ValueType::const_iterator uriIter = tier->begin(),
+ eoi2 = tier->end(); uriIter != eoi2; ++uriIter) {
+ const String* uri = asString(*uriIter);
+ if(uri) {
+ ntier.push_back(util::trim(uri->s()));
}
}
+ if(!ntier.empty()) {
+ torrent->announceList.push_back(ntier);
+ }
}
} else {
- const BDE& announce = rootDict[C_ANNOUNCE];
- BDE announceList = BDE::list();
- if(announce.isString()) {
- announceList << BDE::list();
- announceList[0] << util::trim(announce.s());
+ const String* announce = asString(rootDict->get(C_ANNOUNCE));
+ if(announce) {
+ std::vector<std::string> tier;
+ tier.push_back(util::trim(announce->s()));
+ torrent->announceList.push_back(tier);
}
- torrent[ANNOUNCE_LIST] = announceList;
}
}
-static void extractNodes(BDE& torrent, const BDE& nodesList)
+static void extractNodes
+(const SharedHandle<TorrentAttribute>& torrent, const ValueBase* nodesListSrc)
{
- BDE nodes = BDE::list();
- if(nodesList.isList()) {
- for(BDE::List::const_iterator i = nodesList.listBegin(),
- eoi = nodesList.listEnd(); i != eoi; ++i) {
- const BDE& addrPairList = (*i);
- if(!addrPairList.isList() || addrPairList.size() != 2) {
+ const List* nodesList = asList(nodesListSrc);
+ if(nodesList) {
+ for(List::ValueType::const_iterator i = nodesList->begin(),
+ eoi = nodesList->end(); i != eoi; ++i) {
+ const List* addrPairList = asList(*i);
+ if(!addrPairList || addrPairList->size() != 2) {
continue;
}
- const BDE& hostname = addrPairList[0];
- if(!hostname.isString()) {
+ const String* hostname = asString(addrPairList->get(0));
+ if(!hostname) {
continue;
}
- if(util::trim(hostname.s()).empty()) {
+ if(util::trim(hostname->s()).empty()) {
continue;
}
- const BDE& port = addrPairList[1];
- if(!port.isInteger() || !(0 < port.i() && port.i() < 65536)) {
+ const Integer* port = asInteger(addrPairList->get(1));
+ if(!port || !(0 < port->i() && port->i() < 65536)) {
continue;
}
- BDE node = BDE::dict();
- node[HOSTNAME] = hostname;
- node[PORT] = port;
- nodes << node;
+ torrent->nodes.push_back(std::make_pair(hostname->s(), port->i()));
}
}
- torrent[NODES] = nodes;
}
static void processRootDictionary
(const SharedHandle<DownloadContext>& ctx,
- const BDE& rootDict,
+ const SharedHandle<ValueBase>& root,
const std::string& defaultName,
const std::string& overrideName,
const std::vector<std::string>& uris)
{
- if(!rootDict.isDict()) {
+ const Dict* rootDict = asDict(root);
+ if(!rootDict) {
throw DL_ABORT_EX("torrent file does not contain a root dictionary.");
}
- const BDE& infoDict = rootDict[C_INFO];
- if(!infoDict.isDict()) {
+ const Dict* infoDict = asDict(rootDict->get(C_INFO));
+ if(!infoDict) {
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
C_INFO.c_str()).str());
}
- BDE torrent = BDE::dict();
+ SharedHandle<TorrentAttribute> torrent(new TorrentAttribute());
// retrieve infoHash
- std::string encodedInfoDict = bencode::encode(infoDict);
+ std::string encodedInfoDict = bencode2::encode(infoDict);
unsigned char infoHash[INFO_HASH_LENGTH];
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
MessageDigestContext::SHA1,
encodedInfoDict.data(),
encodedInfoDict.size());
- torrent[INFO_HASH] = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]);
- torrent[METADATA] = encodedInfoDict;
- torrent[METADATA_SIZE] = encodedInfoDict.size();
+ torrent->infoHash = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]);
+ torrent->metadata = encodedInfoDict;
+ torrent->metadataSize = encodedInfoDict.size();
// calculate the number of pieces
- const BDE& piecesData = infoDict[C_PIECES];
- if(!piecesData.isString()) {
+ const String* piecesData = asString(infoDict->get(C_PIECES));
+ if(!piecesData) {
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
C_PIECES.c_str()).str());
}
@@ -397,65 +435,68 @@ static void processRootDictionary
// if(piecesData.s().empty()) {
// throw DL_ABORT_EX("The length of piece hash is 0.");
// }
- size_t numPieces = piecesData.s().size()/PIECE_HASH_LENGTH;
+ size_t numPieces = piecesData->s().size()/PIECE_HASH_LENGTH;
// Commented out to download 0 length torrent.
// if(numPieces == 0) {
// throw DL_ABORT_EX("The number of pieces is 0.");
// }
// retrieve piece length
- const BDE& pieceLengthData = infoDict[C_PIECE_LENGTH];
- if(!pieceLengthData.isInteger()) {
+ const Integer* pieceLengthData = asInteger(infoDict->get(C_PIECE_LENGTH));
+ if(!pieceLengthData) {
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
C_PIECE_LENGTH.c_str()).str());
}
- size_t pieceLength = pieceLengthData.i();
+ size_t pieceLength = pieceLengthData->i();
ctx->setPieceLength(pieceLength);
// retrieve piece hashes
- extractPieceHash(ctx, piecesData.s(), PIECE_HASH_LENGTH, numPieces);
+ extractPieceHash(ctx, piecesData->s(), PIECE_HASH_LENGTH, numPieces);
// private flag
- const BDE& privateData = infoDict[C_PRIVATE];
+ const Integer* privateData = asInteger(infoDict->get(C_PRIVATE));
int privatefg = 0;
- if(privateData.isInteger()) {
- if(privateData.i() == 1) {
+ if(privateData) {
+ if(privateData->i() == 1) {
privatefg = 1;
}
}
- torrent[PRIVATE] = BDE((int64_t)privatefg);
+ if(privatefg) {
+ torrent->privateTorrent = true;
+ }
// retrieve uri-list.
// This implemantation obeys HTTP-Seeding specification:
// see http://www.getright.com/seedtorrent.html
std::vector<std::string> urlList;
- extractUrlList(torrent, urlList, rootDict[C_URL_LIST]);
+ extractUrlList(torrent, urlList, rootDict->get(C_URL_LIST).get());
urlList.insert(urlList.end(), uris.begin(), uris.end());
std::sort(urlList.begin(), urlList.end());
urlList.erase(std::unique(urlList.begin(), urlList.end()), urlList.end());
// retrieve file entries
- extractFileEntries(ctx, torrent, infoDict, defaultName, overrideName, urlList);
+ extractFileEntries
+ (ctx, torrent, infoDict, defaultName, overrideName, urlList);
if((ctx->getTotalLength()+pieceLength-1)/pieceLength != numPieces) {
throw DL_ABORT_EX("Too few/many piece hash.");
}
// retrieve announce
extractAnnounce(torrent, rootDict);
// retrieve nodes
- extractNodes(torrent, rootDict[C_NODES]);
+ extractNodes(torrent, rootDict->get(C_NODES).get());
- const BDE& creationDate = rootDict[C_CREATION_DATE];
- if(creationDate.isInteger()) {
- torrent[CREATION_DATE] = creationDate;
+ const Integer* creationDate = asInteger(rootDict->get(C_CREATION_DATE));
+ if(creationDate) {
+ torrent->creationDate = creationDate->i();
}
- const BDE& commentUtf8 = rootDict[C_COMMENT_UTF8];
- if(commentUtf8.isString()) {
- torrent[COMMENT] = commentUtf8;
+ const String* commentUtf8 = asString(rootDict->get(C_COMMENT_UTF8));
+ if(commentUtf8) {
+ torrent->comment = commentUtf8->s();
} else {
- const BDE& comment = rootDict[C_COMMENT];
- if(comment.isString()) {
- torrent[COMMENT] = comment;
+ const String* comment = asString(rootDict->get(C_COMMENT));
+ if(comment) {
+ torrent->comment = comment->s();
}
}
- const BDE& createdBy = rootDict[C_CREATED_BY];
- if(createdBy.isString()) {
- torrent[CREATED_BY] = createdBy;
+ const String* createdBy = asString(rootDict->get(C_CREATED_BY));
+ if(createdBy) {
+ torrent->createdBy = createdBy->s();
}
ctx->setAttribute(BITTORRENT, torrent);
@@ -466,7 +507,7 @@ void load(const std::string& torrentFile,
const std::string& overrideName)
{
processRootDictionary(ctx,
- bencode::decodeFromFile(torrentFile),
+ bencode2::decodeFromFile(torrentFile),
torrentFile,
overrideName,
std::vector<std::string>());
@@ -478,7 +519,7 @@ void load(const std::string& torrentFile,
const std::string& overrideName)
{
processRootDictionary(ctx,
- bencode::decodeFromFile(torrentFile),
+ bencode2::decodeFromFile(torrentFile),
torrentFile,
overrideName,
uris);
@@ -491,7 +532,7 @@ void loadFromMemory(const unsigned char* content,
const std::string& overrideName)
{
processRootDictionary(ctx,
- bencode::decode(content, length),
+ bencode2::decode(content, length),
defaultName,
overrideName,
std::vector<std::string>());
@@ -505,7 +546,7 @@ void loadFromMemory(const unsigned char* content,
const std::string& overrideName)
{
processRootDictionary(ctx,
- bencode::decode(content, length),
+ bencode2::decode(content, length),
defaultName,
overrideName,
uris);
@@ -518,7 +559,7 @@ void loadFromMemory(const std::string& context,
{
processRootDictionary
(ctx,
- bencode::decode(context),
+ bencode2::decode(context),
defaultName, overrideName,
std::vector<std::string>());
}
@@ -531,73 +572,82 @@ void loadFromMemory(const std::string& context,
{
processRootDictionary
(ctx,
- bencode::decode(context),
+ bencode2::decode(context),
defaultName, overrideName,
uris);
}
+SharedHandle<TorrentAttribute> getTorrentAttrs
+(const SharedHandle<DownloadContext>& dctx)
+{
+ return static_pointer_cast<TorrentAttribute>(dctx->getAttribute(BITTORRENT));
+}
+
const unsigned char*
-getInfoHash(const SharedHandle<DownloadContext>& downloadContext)
+getInfoHash(const SharedHandle<DownloadContext>& dctx)
{
- return downloadContext->getAttribute(BITTORRENT)[INFO_HASH].uc();
+ return reinterpret_cast<const unsigned char*>
+ (getTorrentAttrs(dctx)->infoHash.data());
}
std::string
-getInfoHashString(const SharedHandle<DownloadContext>& downloadContext)
+getInfoHashString(const SharedHandle<DownloadContext>& dctx)
{
- return util::toHex(downloadContext->getAttribute(BITTORRENT)[INFO_HASH].s());
+ return util::toHex(getTorrentAttrs(dctx)->infoHash);
}
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx)
{
- const BDE& torrentAttrs = dctx->getAttribute(BITTORRENT);
+ SharedHandle<TorrentAttribute> torrentAttrs = getTorrentAttrs(dctx);
o << "*** BitTorrent File Information ***" << "\n";
- if(torrentAttrs.containsKey(COMMENT)) {
- o << "Comment: " << torrentAttrs[COMMENT].s() << "\n";
+ if(!torrentAttrs->comment.empty()) {
+ o << "Comment: " << torrentAttrs->comment << "\n";
}
- if(torrentAttrs.containsKey(CREATION_DATE)) {
+ if(torrentAttrs->creationDate) {
struct tm* staticNowtmPtr;
char buf[26];
- time_t t = torrentAttrs[CREATION_DATE].i();
+ time_t t = torrentAttrs->creationDate;
if((staticNowtmPtr = localtime(&t)) != 0 &&
asctime_r(staticNowtmPtr, buf) != 0) {
// buf includes "\n"
o << "Creation Date: " << buf;
}
}
- if(torrentAttrs.containsKey(CREATED_BY)) {
- o << "Created By: " << torrentAttrs[CREATED_BY].s() << "\n";
+ if(!torrentAttrs->createdBy.empty()) {
+ o << "Created By: " << torrentAttrs->createdBy << "\n";
}
- o << "Mode: " << torrentAttrs[MODE].s() << "\n";
+ o << "Mode: " << torrentAttrs->mode << "\n";
o << "Announce:" << "\n";
- const BDE& announceList = torrentAttrs[ANNOUNCE_LIST];
- for(BDE::List::const_iterator tieritr = announceList.listBegin(),
- eoi = announceList.listEnd(); tieritr != eoi; ++tieritr) {
- if(!(*tieritr).isList()) {
- continue;
- }
- for(BDE::List::const_iterator i = (*tieritr).listBegin(),
- eoi2 = (*tieritr).listEnd(); i != eoi2; ++i) {
- o << " " << (*i).s();
+ for(std::vector<std::vector<std::string> >::const_iterator tierIter =
+ torrentAttrs->announceList.begin(),
+ eoi = torrentAttrs->announceList.end(); tierIter != eoi; ++tierIter) {
+ for(std::vector<std::string>::const_iterator i = (*tierIter).begin(),
+ eoi2 = (*tierIter).end(); i != eoi2; ++i) {
+ o << " " << *i;
}
o << "\n";
}
- o << "Info Hash: " << util::toHex(torrentAttrs[INFO_HASH].s()) << "\n";
- o << "Piece Length: " << util::abbrevSize(dctx->getPieceLength()) << "B\n";
- o << "The Number of Pieces: " << dctx->getNumPieces() << "\n";
- o << "Total Length: " << util::abbrevSize(dctx->getTotalLength()) << "B ("
+ o << "Info Hash: "
+ << util::toHex(torrentAttrs->infoHash) << "\n"
+ << "Piece Length: "
+ << util::abbrevSize(dctx->getPieceLength()) << "B\n"
+ << "The Number of Pieces: "
+ << dctx->getNumPieces() << "\n"
+ << "Total Length: "
+ << util::abbrevSize(dctx->getTotalLength()) << "B ("
<< util::uitos(dctx->getTotalLength(), true) << ")\n";
- if(!torrentAttrs[URL_LIST].empty()) {
- const BDE& urlList = torrentAttrs[URL_LIST];
+ if(!torrentAttrs->urlList.empty()) {
o << "URL List: " << "\n";
- for(BDE::List::const_iterator i = urlList.listBegin(),
- eoi = urlList.listEnd(); i != eoi; ++i) {
- o << " " << (*i).s() << "\n";
+ for(std::vector<std::string>::const_iterator i =
+ torrentAttrs->urlList.begin(),
+ eoi = torrentAttrs->urlList.end(); i != eoi; ++i) {
+ o << " " << *i << "\n";
}
}
- o << "Name: " << torrentAttrs[NAME].s() << "\n";
- o << "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n";
- util::toStream(dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o);
+ o << "Name: " << torrentAttrs->name << "\n"
+ << "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n";
+ util::toStream
+ (dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o);
}
void computeFastSet
@@ -857,22 +907,23 @@ void assertID
}
}
-BDE parseMagnet(const std::string& magnet)
+SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet)
{
- BDE result;
- BDE r = magnet::parse(magnet);
- if(r.isNone()) {
+ SharedHandle<Dict> r = magnet::parse(magnet);
+ if(r.isNull()) {
throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
}
- if(!r.containsKey("xt")) {
+ const List* xts = asList(r->get("xt"));
+ if(!xts) {
throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
}
+ SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
std::string infoHash;
- const BDE& xts = r["xt"];
- for(BDE::List::const_iterator xtiter = xts.listBegin(),
- eoi = xts.listEnd(); xtiter != eoi && infoHash.empty(); ++xtiter) {
- if(util::startsWith((*xtiter).s(), "urn:btih:")) {
- std::string xtarg = (*xtiter).s().substr(9);
+ for(List::ValueType::const_iterator xtiter = xts->begin(),
+ eoi = xts->end(); xtiter != eoi && infoHash.empty(); ++xtiter) {
+ const String* xt = asString(*xtiter);
+ if(util::startsWith(xt->s(), "urn:btih:")) {
+ std::string xtarg = xt->s().substr(9);
size_t size = xtarg.size();
if(size == 32) {
std::string rawhash = base32::decode(xtarg);
@@ -891,74 +942,82 @@ BDE parseMagnet(const std::string& magnet)
throw DL_ABORT_EX("Bad BitTorrent Magnet URI. "
"No valid BitTorrent Info Hash found.");
}
- BDE announceList = BDE::list();
- if(r.containsKey("tr")) {
- const BDE& uris = r["tr"];
- for(BDE::List::const_iterator i = uris.listBegin(), eoi = uris.listEnd();
+ const List* trs = asList(r->get("tr"));
+ if(trs) {
+ for(List::ValueType::const_iterator i = trs->begin(), eoi = trs->end();
i != eoi; ++i) {
- BDE tier = BDE::list();
- tier << *i;
- announceList << tier;
+ std::vector<std::string> tier;
+ tier.push_back(asString(*i)->s());
+ attrs->announceList.push_back(tier);
}
}
std::string name = "[METADATA]";
- if(r.containsKey("dn") && r["dn"].size()) {
- name += r["dn"][0].s();
+ const List* dns = asList(r->get("dn"));
+ if(dns && !dns->empty()) {
+ const String* dn = asString(dns->get(0));
+ name += dn->s();
} else {
name += util::toHex(infoHash);
}
- BDE attrs = BDE::dict();
- attrs[INFO_HASH] = infoHash;
- attrs[NAME] = name;
- attrs[ANNOUNCE_LIST] = announceList;
- result = attrs;
- return result;
+ attrs->infoHash = infoHash;
+ attrs->name = name;
+ return attrs;
}
void loadMagnet
(const std::string& magnet, const SharedHandle<DownloadContext>& dctx)
{
- BDE attrs = parseMagnet(magnet);
+ SharedHandle<TorrentAttribute> attrs = parseMagnet(magnet);
dctx->setAttribute(BITTORRENT, attrs);
}
-std::string metadata2Torrent(const std::string& metadata, const BDE& attrs)
+std::string metadata2Torrent
+(const std::string& metadata, const SharedHandle<TorrentAttribute>& attrs)
{
std::string torrent = "d";
- if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) {
- const BDE& announceList = attrs[bittorrent::ANNOUNCE_LIST];
- if(announceList.size() > 0) {
- torrent += "13:announce-list";
- torrent += bencode::encode(announceList);
+
+ List announceList;
+ for(std::vector<std::vector<std::string> >::const_iterator tierIter =
+ attrs->announceList.begin(),
+ eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) {
+ SharedHandle<List> tier = List::g();
+ for(std::vector<std::string>::const_iterator uriIter = (*tierIter).begin(),
+ eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) {
+ tier->append(String::g(*uriIter));
+ }
+ if(!tier->empty()) {
+ announceList.append(tier);
}
}
+ if(!announceList.empty()) {
+ torrent += "13:announce-list";
+ torrent += bencode2::encode(&announceList);
+ }
torrent +=
strconcat("4:info", metadata, "e");
return torrent;
}
-std::string torrent2Magnet(const BDE& attrs)
+std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs)
{
std::string uri = "magnet:?";
- if(attrs.containsKey(INFO_HASH)) {
+ if(!attrs->infoHash.empty()) {
uri += "xt=urn:btih:";
- uri += util::toUpper(util::toHex(attrs[INFO_HASH].s()));
+ uri += util::toUpper(util::toHex(attrs->infoHash));
} else {
return A2STR::NIL;
}
- if(attrs.containsKey(NAME)) {
+ if(!attrs->name.empty()) {
uri += "&dn=";
- uri += util::percentEncode(attrs[NAME].s());
- }
- if(attrs.containsKey(ANNOUNCE_LIST)) {
- const BDE& tiers = attrs[ANNOUNCE_LIST];
- for(BDE::List::const_iterator tieriter = tiers.listBegin(),
- eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) {
- for(BDE::List::const_iterator uriiter = (*tieriter).listBegin(),
- eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) {
- uri += "&tr=";
- uri += util::percentEncode((*uriiter).s());
- }
+ uri += util::percentEncode(attrs->name);
+ }
+ for(std::vector<std::vector<std::string> >::const_iterator tierIter =
+ attrs->announceList.begin(),
+ eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) {
+ for(std::vector<std::string>::const_iterator uriIter = (*tierIter).begin(),
+ eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) {
+ uri += "&tr=";
+ uri += util::percentEncode(*uriIter);
}
}
return uri;
diff --git a/src/bittorrent_helper.h b/src/bittorrent_helper.h
index 0a7e4c19..3eacc438 100644
--- a/src/bittorrent_helper.h
+++ b/src/bittorrent_helper.h
@@ -43,8 +43,8 @@
#include "SharedHandle.h"
#include "AnnounceTier.h"
-#include "BDE.h"
#include "util.h"
+#include "TorrentAttribute.h"
namespace aria2 {
@@ -118,15 +118,16 @@ void loadFromMemory(const std::string& context,
const std::string& defaultName,
const std::string& overrideName = "");
-// Parses BitTorrent Magnet URI and returns BDE::dict() which includes
-// infoHash, name and announceList. If parsing operation failed, an
-// RecoverableException will be thrown. infoHash and name are string
-// and announceList is a list of list of announce URI.
+// Parses BitTorrent Magnet URI and returns
+// SharedHandle<TorrentAttribute> which includes infoHash, name and
+// announceList. If parsing operation failed, an RecoverableException
+// will be thrown. infoHash and name are string and announceList is a
+// list of list of announce URI.
//
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii string,
// or 32bytes Base32 encoded string.
-BDE parseMagnet(const std::string& magnet);
+SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet);
// Parses BitTorrent Magnet URI and set them in ctx as a
// bittorrent::BITTORRENT attibute. If parsing operation failed, an
@@ -161,6 +162,9 @@ void computeFastSet
// Writes the detailed information about torrent loaded in dctx.
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx);
+SharedHandle<TorrentAttribute> getTorrentAttrs
+(const SharedHandle<DownloadContext>& dctx);
+
// Returns the value associated with INFO_HASH key in BITTORRENT
// attribute.
const unsigned char*
@@ -227,14 +231,13 @@ void assertPayloadLengthEqual
void assertID
(uint8_t expected, const unsigned char* data, const std::string& msgName);
-// Converts attrs into torrent data. attrs must be a BDE::dict. This
-// function does not guarantee the returned string is valid torrent
-// data.
-std::string metadata2Torrent(const std::string& metadata, const BDE& attrs);
+// Converts attrs into torrent data. This function does not guarantee
+// the returned string is valid torrent data.
+std::string metadata2Torrent
+(const std::string& metadata, const SharedHandle<TorrentAttribute>& attrs);
-// Constructs BitTorrent Magnet URI using attrs. attrs must be a
-// BDE::dict.
-std::string torrent2Magnet(const BDE& attrs);
+// Constructs BitTorrent Magnet URI using attrs.
+std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs);
} // namespace bittorrent
diff --git a/src/download_helper.cc b/src/download_helper.cc
index 571a317e..16a2de78 100644
--- a/src/download_helper.cc
+++ b/src/download_helper.cc
@@ -276,8 +276,9 @@ createBtMagnetRequestGroup(const std::string& magnetLink,
rg->setFileAllocationEnabled(false);
rg->setPreLocalFileCheckEnabled(false);
bittorrent::loadMagnet(magnetLink, dctx);
- dctx->getFirstFileEntry()->setPath
- (dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s());
+ SharedHandle<TorrentAttribute> torrentAttrs =
+ bittorrent::getTorrentAttrs(dctx);
+ dctx->getFirstFileEntry()->setPath(torrentAttrs->name);
rg->setDownloadContext(dctx);
rg->clearPostDownloadHandler();
rg->addPostDownloadHandler
diff --git a/src/magnet.cc b/src/magnet.cc
index 3118bf64..389a4c3f 100644
--- a/src/magnet.cc
+++ b/src/magnet.cc
@@ -39,31 +39,31 @@ namespace aria2 {
namespace magnet {
-BDE parse(const std::string& magnet)
+SharedHandle<Dict> parse(const std::string& magnet)
{
- BDE result;
+ SharedHandle<Dict> dict;
if(!util::startsWith(magnet, "magnet:?")) {
- return result;
+ return dict;
}
+ dict.reset(new Dict());
std::vector<std::string> queries;
util::split(std::string(magnet.begin()+8, magnet.end()),
std::back_inserter(queries), "&");
- BDE dict = BDE::dict();
for(std::vector<std::string>::const_iterator i = queries.begin(),
eoi = queries.end(); i != eoi; ++i) {
std::pair<std::string, std::string> kv;
util::split(kv, *i, '=');
std::string value = util::percentDecode(kv.second);
- if(dict.containsKey(kv.first)) {
- dict[kv.first] << value;
+ List* l = asList(dict->get(kv.first));
+ if(l) {
+ l->append(String::g(value));
} else {
- BDE list = BDE::list();
- list << value;
- dict[kv.first] = list;
+ SharedHandle<List> l = List::g();
+ l->append(String::g(value));
+ dict->put(kv.first, l);
}
}
- result = dict;
- return result;
+ return dict;
}
} // namespace magnet
diff --git a/src/magnet.h b/src/magnet.h
index 4cf5d5e2..ea7cd2be 100644
--- a/src/magnet.h
+++ b/src/magnet.h
@@ -36,17 +36,18 @@
#define _D_MAGNET_H_
#include "common.h"
-#include "BDE.h"
+#include "ValueBase.h"
namespace aria2 {
namespace magnet {
-// Parses Magnet URI magnet and stores parameters in BDE::dict().
-// Because same parameter name can appear more than once, the value
-// associated with a key is BDE::list(). A parameter value is stored
-// in a list. If parsing operation failed, BDE::none is returned.
-BDE parse(const std::string& magnet);
+// Parses Magnet URI magnet and stores parameters in
+// SharedHandle<Dict>. Because same parameter name can appear more
+// than once, the value associated with a key is SharedHandle<List>. A
+// parameter value is stored in a list. If parsing operation failed,
+// SharedHandle<Dict>() is returned.
+SharedHandle<Dict> parse(const std::string& magnet);
} // namespace magnet