2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Added Base32 encoded BitTorrent Magnet Link support.
	* src/Makefile.am
	* src/base32.cc
	* src/base32.h
	* src/bittorrent_helper.cc
	* test/Base32Test.cc
	* test/BittorrentHelperTest.cc
	* test/Makefile.am
pull/1/head
Tatsuhiro Tsujikawa 2009-11-23 15:59:31 +00:00
parent 6e8074c087
commit 894165171c
10 changed files with 298 additions and 29 deletions

View File

@ -1,3 +1,14 @@
2009-11-24 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added Base32 encoded BitTorrent Magnet Link support.
* src/Makefile.am
* src/base32.cc
* src/base32.h
* src/bittorrent_helper.cc
* test/Base32Test.cc
* test/BittorrentHelperTest.cc
* test/Makefile.am
2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added BitTorrent Magnet Link support. Base32 encoded link is not

View File

@ -50,6 +50,7 @@ SRCS = Socket.h\
File.cc File.h\
Option.cc Option.h\
Base64.cc Base64.h\
base32.cc base32.h\
LogFactory.cc LogFactory.h\
TimeA2.cc TimeA2.h\
SharedHandle.h\

View File

@ -328,14 +328,15 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
AbstractDiskWriter.cc AbstractDiskWriter.h \
DefaultDiskWriter.cc DefaultDiskWriter.h \
DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \
File.h Option.cc Option.h Base64.cc Base64.h LogFactory.cc \
LogFactory.h TimeA2.cc TimeA2.h SharedHandle.h \
HandleRegistry.h FeatureConfig.cc FeatureConfig.h \
DownloadEngineFactory.cc DownloadEngineFactory.h SpeedCalc.cc \
SpeedCalc.h PeerStat.h BitfieldMan.cc BitfieldMan.h \
BitfieldManFactory.cc BitfieldManFactory.h Randomizer.h \
SimpleRandomizer.cc SimpleRandomizer.h HttpResponse.cc \
HttpResponse.h HttpRequest.cc HttpRequest.h Range.h \
File.h Option.cc Option.h Base64.cc Base64.h base32.cc \
base32.h LogFactory.cc LogFactory.h TimeA2.cc TimeA2.h \
SharedHandle.h HandleRegistry.h FeatureConfig.cc \
FeatureConfig.h DownloadEngineFactory.cc \
DownloadEngineFactory.h SpeedCalc.cc SpeedCalc.h PeerStat.h \
BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \
BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \
SimpleRandomizer.h HttpResponse.cc HttpResponse.h \
HttpRequest.cc HttpRequest.h Range.h \
AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \
AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \
Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \
@ -769,11 +770,12 @@ am__objects_27 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
SimpleLogger.$(OBJEXT) AbstractDiskWriter.$(OBJEXT) \
DefaultDiskWriter.$(OBJEXT) DefaultDiskWriterFactory.$(OBJEXT) \
File.$(OBJEXT) Option.$(OBJEXT) Base64.$(OBJEXT) \
LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) FeatureConfig.$(OBJEXT) \
DownloadEngineFactory.$(OBJEXT) SpeedCalc.$(OBJEXT) \
BitfieldMan.$(OBJEXT) BitfieldManFactory.$(OBJEXT) \
SimpleRandomizer.$(OBJEXT) HttpResponse.$(OBJEXT) \
HttpRequest.$(OBJEXT) AbstractProxyRequestCommand.$(OBJEXT) \
base32.$(OBJEXT) LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) \
FeatureConfig.$(OBJEXT) DownloadEngineFactory.$(OBJEXT) \
SpeedCalc.$(OBJEXT) BitfieldMan.$(OBJEXT) \
BitfieldManFactory.$(OBJEXT) SimpleRandomizer.$(OBJEXT) \
HttpResponse.$(OBJEXT) HttpRequest.$(OBJEXT) \
AbstractProxyRequestCommand.$(OBJEXT) \
AbstractProxyResponseCommand.$(OBJEXT) Netrc.$(OBJEXT) \
AuthConfig.$(OBJEXT) AbstractAuthResolver.$(OBJEXT) \
DefaultAuthResolver.$(OBJEXT) NetrcAuthResolver.$(OBJEXT) \
@ -1071,14 +1073,15 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
AbstractDiskWriter.cc AbstractDiskWriter.h \
DefaultDiskWriter.cc DefaultDiskWriter.h \
DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \
File.h Option.cc Option.h Base64.cc Base64.h LogFactory.cc \
LogFactory.h TimeA2.cc TimeA2.h SharedHandle.h \
HandleRegistry.h FeatureConfig.cc FeatureConfig.h \
DownloadEngineFactory.cc DownloadEngineFactory.h SpeedCalc.cc \
SpeedCalc.h PeerStat.h BitfieldMan.cc BitfieldMan.h \
BitfieldManFactory.cc BitfieldManFactory.h Randomizer.h \
SimpleRandomizer.cc SimpleRandomizer.h HttpResponse.cc \
HttpResponse.h HttpRequest.cc HttpRequest.h Range.h \
File.h Option.cc Option.h Base64.cc Base64.h base32.cc \
base32.h LogFactory.cc LogFactory.h TimeA2.cc TimeA2.h \
SharedHandle.h HandleRegistry.h FeatureConfig.cc \
FeatureConfig.h DownloadEngineFactory.cc \
DownloadEngineFactory.h SpeedCalc.cc SpeedCalc.h PeerStat.h \
BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \
BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \
SimpleRandomizer.h HttpResponse.cc HttpResponse.h \
HttpRequest.cc HttpRequest.h Range.h \
AbstractProxyRequestCommand.cc AbstractProxyRequestCommand.h \
AbstractProxyResponseCommand.cc AbstractProxyResponseCommand.h \
Netrc.cc Netrc.h AuthConfig.cc AuthConfig.h AuthResolver.h \
@ -1558,6 +1561,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcResponse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ZeroBtMessage.Po@am__quote@
@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)/bitfield.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@

134
src/base32.cc Normal file
View File

@ -0,0 +1,134 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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 "base32.h"
#include "util.h"
namespace aria2 {
namespace base32 {
static const char B32TABLE[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7'
};
std::string encode(const std::string& src)
{
std::string ret;
size_t count = 0;
uint64_t buf = 0;
for(size_t i = 0; i < src.size(); ++i) {
buf <<= 8;
buf += src[i]&0xff;
++count;
if(count == 5) {
char temp[8];
for(size_t j = 0; j < 8; ++j) {
temp[7-j] = B32TABLE[buf&0x1f];
buf >>= 5;
}
ret += std::string(&temp[0], &temp[8]);
count = 0;
buf = 0;
}
}
size_t r = 0;
if(count == 1) {
buf <<= 2;
r = 2;
} else if(count == 2) {
buf <<= 4;
r = 4;
} else if(count == 3) {
buf <<= 1;
r = 5;
} else if(count == 4) {
buf <<= 3;
r = 7;
}
char temp[7];
for(size_t j = 0; j < r; ++j) {
temp[r-1-j] = B32TABLE[buf&0x1f];
buf >>= 5;
}
ret += std::string(&temp[0], &temp[r]);
if(r) {
ret += std::string(8-r, '=');
}
return ret;
}
std::string decode(const std::string& src)
{
std::string ret;
if(src.size()%8) {
return ret;
}
bool done = false;
for(size_t i = 0; i < src.size() && !done; i += 8) {
uint64_t buf = 0;
size_t bits = 0;
for(size_t j = 0; j < 8; ++j) {
char ch = src[i+j];
unsigned char value;
if('A' <= ch && ch <= 'Z') {
value = ch-'A';
} else if('2' <= ch && ch <= '7') {
value = ch-'2'+26;
} else if(ch == '=') {
done = true;
break;
} else {
ret.clear();
return ret;
}
buf <<= 5;
buf += value;
bits += 5;
}
buf >>= (bits%8);
bits = bits/8*8;
buf = ntoh64(buf);
char* p = reinterpret_cast<char*>(&buf);
ret += std::string(&p[(64-bits)/8], &p[8]);
}
return ret;
}
} // namespace base32
} // namespace aria2

54
src/base32.h Normal file
View File

@ -0,0 +1,54 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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_BASE32_H_
#define _D_BASE32_H_
#include "common.h"
#include <string>
namespace aria2 {
namespace base32 {
std::string encode(const std::string& src);
std::string decode(const std::string& src);
} // namespace base32
} // namespace aria2
#endif // _D_BASE32_H_

View File

@ -52,6 +52,7 @@
#include "a2netcompat.h"
#include "BtConstants.h"
#include "bitfield.h"
#include "base32.h"
namespace aria2 {
@ -883,8 +884,11 @@ void parseMagnetLink(const std::string& magnetLink,
}
}
if(infoHash.size() == 32) {
// Not yet implemented
abort();
std::string rawhash = base32::decode(infoHash);
if(rawhash.size() != 20) {
throw DL_ABORT_EX("Invalid info hash");
}
infoHash = rawhash;
} else if(infoHash.size() == 40) {
std::string rawhash = util::fromHex(infoHash);
if(rawhash.empty()) {

45
test/Base32Test.cc Normal file
View File

@ -0,0 +1,45 @@
#include "base32.h"
#include <cppunit/extensions/HelperMacros.h>
#include "util.h"
namespace aria2 {
class Base32Test:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(Base32Test);
CPPUNIT_TEST(testEncode);
CPPUNIT_TEST(testDecode);
CPPUNIT_TEST_SUITE_END();
public:
void testEncode();
void testDecode();
};
CPPUNIT_TEST_SUITE_REGISTRATION( Base32Test );
void Base32Test::testEncode()
{
CPPUNIT_ASSERT_EQUAL(std::string(), base32::encode(""));
CPPUNIT_ASSERT_EQUAL(std::string("GE======"), base32::encode("1"));
CPPUNIT_ASSERT_EQUAL(std::string("GEZA===="), base32::encode("12"));
CPPUNIT_ASSERT_EQUAL(std::string("GEZDG==="), base32::encode("123"));
CPPUNIT_ASSERT_EQUAL(std::string("GEZDGNA="), base32::encode("1234"));
CPPUNIT_ASSERT_EQUAL(std::string("GEZDGNBV"), base32::encode("12345"));
CPPUNIT_ASSERT_EQUAL(std::string("ESGQUHGQQKCA===="),
base32::encode(util::fromHex("248d0a1cd08284")));
}
void Base32Test::testDecode()
{
CPPUNIT_ASSERT_EQUAL(std::string(), base32::decode(""));
CPPUNIT_ASSERT_EQUAL(std::string("1"), base32::decode("GE======"));
CPPUNIT_ASSERT_EQUAL(std::string("12"), base32::decode("GEZA===="));
CPPUNIT_ASSERT_EQUAL(std::string("123"), base32::decode("GEZDG==="));
CPPUNIT_ASSERT_EQUAL(std::string("1234"), base32::decode("GEZDGNA="));
CPPUNIT_ASSERT_EQUAL(std::string("12345"), base32::decode("GEZDGNBV"));
}
} // namespace aria2

View File

@ -16,6 +16,7 @@
#include "a2netcompat.h"
#include "bencode.h"
#include "TestUtil.h"
#include "base32.h"
namespace aria2 {
@ -59,6 +60,7 @@ class BittorrentHelperTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testCheckBitfield);
CPPUNIT_TEST(testMetadata);
CPPUNIT_TEST(testParseMagnetLink);
CPPUNIT_TEST(testParseMagnetLink_base32);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
@ -99,6 +101,7 @@ public:
void testCheckBitfield();
void testMetadata();
void testParseMagnetLink();
void testParseMagnetLink_base32();
};
@ -715,6 +718,17 @@ void BittorrentHelperTest::testParseMagnetLink()
attrs[bittorrent::NAME].s());
}
void BittorrentHelperTest::testParseMagnetLink_base32()
{
std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c";
std::string base32InfoHash = base32::encode(util::fromHex(infoHash));
SharedHandle<DownloadContext> dctx(new DownloadContext());
std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
bittorrent::parseMagnetLink(magnet, dctx);
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
bittorrent::getInfoHashString(dctx));
}
} // namespace bittorrent
} // namespace aria2

View File

@ -5,6 +5,7 @@ aria2c_SOURCES = AllTest.cc\
SocketCoreTest.cc\
array_funTest.cc\
Base64Test.cc\
Base32Test.cc\
SequenceTest.cc\
a2functionalTest.cc\
FileEntryTest.cc\

View File

@ -177,7 +177,7 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = aria2c$(EXEEXT)
am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
SocketCoreTest.cc array_funTest.cc Base64Test.cc \
SocketCoreTest.cc array_funTest.cc Base64Test.cc Base32Test.cc \
SequenceTest.cc a2functionalTest.cc FileEntryTest.cc \
PieceTest.cc SegmentTest.cc GrowSegmentTest.cc \
SingleFileAllocationIteratorTest.cc \
@ -355,10 +355,10 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
@ENABLE_METALINK_TRUE@ MetalinkProcessorTest.$(OBJEXT)
am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
SocketCoreTest.$(OBJEXT) array_funTest.$(OBJEXT) \
Base64Test.$(OBJEXT) SequenceTest.$(OBJEXT) \
a2functionalTest.$(OBJEXT) FileEntryTest.$(OBJEXT) \
PieceTest.$(OBJEXT) SegmentTest.$(OBJEXT) \
GrowSegmentTest.$(OBJEXT) \
Base64Test.$(OBJEXT) Base32Test.$(OBJEXT) \
SequenceTest.$(OBJEXT) a2functionalTest.$(OBJEXT) \
FileEntryTest.$(OBJEXT) PieceTest.$(OBJEXT) \
SegmentTest.$(OBJEXT) GrowSegmentTest.$(OBJEXT) \
SingleFileAllocationIteratorTest.$(OBJEXT) \
DefaultBtProgressInfoFileTest.$(OBJEXT) \
RequestGroupTest.$(OBJEXT) PStringBuildVisitorTest.$(OBJEXT) \
@ -596,7 +596,7 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
array_funTest.cc Base64Test.cc SequenceTest.cc \
array_funTest.cc Base64Test.cc Base32Test.cc SequenceTest.cc \
a2functionalTest.cc FileEntryTest.cc PieceTest.cc \
SegmentTest.cc GrowSegmentTest.cc \
SingleFileAllocationIteratorTest.cc \
@ -726,6 +726,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AuthConfigFactoryTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BDETest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BNodeTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base32Test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@