| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
20
|
|
|
20
|
|
88870
|
use v5.40; |
|
|
20
|
|
|
|
|
86
|
|
|
2
|
20
|
|
|
20
|
|
127
|
use feature 'class'; |
|
|
20
|
|
|
|
|
42
|
|
|
|
20
|
|
|
|
|
3061
|
|
|
3
|
20
|
|
|
20
|
|
134
|
no warnings 'experimental::class'; |
|
|
20
|
|
|
|
|
59
|
|
|
|
20
|
|
|
|
|
1197
|
|
|
4
|
20
|
|
|
20
|
|
585
|
use Net::BitTorrent::Emitter; |
|
|
20
|
|
|
|
|
59
|
|
|
|
20
|
|
|
|
|
2476
|
|
|
5
|
|
|
|
|
|
|
# |
|
6
|
|
|
|
|
|
|
class Net::BitTorrent::Protocol::BEP53 v2.0.0 : isa(Net::BitTorrent::Emitter) { |
|
7
|
20
|
|
|
20
|
|
666
|
use URI::Escape qw[uri_unescape uri_escape]; |
|
|
20
|
|
|
|
|
1584
|
|
|
|
20
|
|
|
|
|
30259
|
|
|
8
|
|
|
|
|
|
|
# |
|
9
|
|
|
|
|
|
|
field $infohash_v1 : reader : param = undef; |
|
10
|
|
|
|
|
|
|
field $infohash_v2 : reader : param = undef; |
|
11
|
|
|
|
|
|
|
field $trackers : reader : param = []; |
|
12
|
|
|
|
|
|
|
field $name : reader : param = undef; |
|
13
|
|
|
|
|
|
|
field $nodes : reader : param = []; # DHT bootstrap nodes (x.pe) |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# |
|
16
|
13
|
|
|
13
|
1
|
262062
|
sub parse ( $class, $uri ) { |
|
|
13
|
|
|
|
|
31
|
|
|
|
13
|
|
|
|
|
26
|
|
|
|
13
|
|
|
|
|
23
|
|
|
17
|
13
|
50
|
|
|
|
85
|
die 'Not a magnet URI' unless $uri =~ /^magnet:\?/; |
|
18
|
13
|
|
|
|
|
37
|
my %params; |
|
19
|
13
|
|
|
|
|
46
|
my $query = substr( $uri, 8 ); |
|
20
|
13
|
|
|
|
|
75
|
for my $pair ( split( /[&;]/, $query ) ) { |
|
21
|
19
|
|
|
|
|
86
|
my ( $key, $val ) = split( /=/, $pair, 2 ); |
|
22
|
19
|
50
|
33
|
|
|
107
|
next unless defined $key && defined $val; |
|
23
|
19
|
|
|
|
|
123
|
$val = uri_unescape($val); |
|
24
|
19
|
|
|
|
|
203
|
push @{ $params{$key} }, $val; |
|
|
19
|
|
|
|
|
99
|
|
|
25
|
|
|
|
|
|
|
} |
|
26
|
13
|
|
|
|
|
30
|
my ( $v1, $v2 ); |
|
27
|
13
|
|
50
|
|
|
33
|
for my $xt ( @{ $params{xt} // [] } ) { |
|
|
13
|
|
|
|
|
81
|
|
|
28
|
15
|
100
|
|
|
|
102
|
if ( $xt =~ /^urn:btih:([a-fA-F0-9]{40})$/ ) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
29
|
12
|
|
|
|
|
120
|
$v1 = pack( 'H*', $1 ); |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
elsif ( $xt =~ /^urn:btih:([a-zA-Z2-7]{32})$/ ) { |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Base32 encoded (v1) |
|
34
|
0
|
|
|
|
|
0
|
$v1 = _decode_base32($1); |
|
35
|
|
|
|
|
|
|
} |
|
36
|
|
|
|
|
|
|
elsif ( $xt =~ /^urn:btmh:1220([a-fA-F0-9]{64})$/ ) { |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# BEP 53 v2 (multihash SHA-256) |
|
39
|
3
|
|
|
|
|
16
|
$v2 = pack( 'H*', $1 ); |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
return $class->new( |
|
43
|
|
|
|
|
|
|
infohash_v1 => $v1, |
|
44
|
|
|
|
|
|
|
infohash_v2 => $v2, |
|
45
|
|
|
|
|
|
|
trackers => ( $params{tr} // [] ), |
|
46
|
|
|
|
|
|
|
name => ( $params{dn}[0] // undef ), |
|
47
|
13
|
|
50
|
|
|
371
|
nodes => ( $params{'x.pe'} // [] ), |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
48
|
|
|
|
|
|
|
); |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
0
|
|
|
0
|
|
|
sub _decode_base32 ($str) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
$str = uc($str); |
|
53
|
0
|
|
|
|
|
|
my $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; |
|
54
|
0
|
|
|
|
|
|
my %map; |
|
55
|
0
|
|
|
|
|
|
@map{ split //, $alphabet } = 0 .. 31; |
|
56
|
0
|
|
|
|
|
|
my $buffer = 0; |
|
57
|
0
|
|
|
|
|
|
my $bits = 0; |
|
58
|
0
|
|
|
|
|
|
my $res = ''; |
|
59
|
0
|
|
|
|
|
|
for my $char ( split //, $str ) { |
|
60
|
0
|
0
|
|
|
|
|
next unless exists $map{$char}; |
|
61
|
0
|
|
|
|
|
|
$buffer = ( $buffer << 5 ) | $map{$char}; |
|
62
|
0
|
|
|
|
|
|
$bits += 5; |
|
63
|
0
|
0
|
|
|
|
|
if ( $bits >= 8 ) { |
|
64
|
0
|
|
|
|
|
|
$bits -= 8; |
|
65
|
0
|
|
|
|
|
|
$res .= chr( ( $buffer >> $bits ) & 0xFF ); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
} |
|
68
|
0
|
|
|
|
|
|
return $res; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
method to_string () { |
|
72
|
|
|
|
|
|
|
my @pairs; |
|
73
|
|
|
|
|
|
|
push @pairs, 'xt=urn:btih:' . unpack( 'H*', $infohash_v1 ) if $infohash_v1; |
|
74
|
|
|
|
|
|
|
push @pairs, 'xt=urn:btmh:1220' . unpack( 'H*', $infohash_v2 ) if $infohash_v2; |
|
75
|
|
|
|
|
|
|
push @pairs, 'dn=' . uri_escape($name) if defined $name; |
|
76
|
|
|
|
|
|
|
push @pairs, 'tr=' . uri_escape($_) for @$trackers; |
|
77
|
|
|
|
|
|
|
push @pairs, 'x.pe=' . uri_escape($_) for @$nodes; |
|
78
|
|
|
|
|
|
|
'magnet:?' . join( '&', @pairs ); |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
}; |
|
81
|
|
|
|
|
|
|
# |
|
82
|
|
|
|
|
|
|
1; |