line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl -w |
2
|
|
|
|
|
|
|
package Convert::Bencode; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Convert::Bencode - Functions for converting to/from bencoded strings |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 SYNOPSIS |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use Convert::Bencode qw(bencode bdecode); |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
my $string = "d4:ainti12345e3:key5:value4:type4:teste"; |
13
|
|
|
|
|
|
|
my $hashref = bdecode($string); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
foreach my $key (keys(%{$hashref})) { |
16
|
|
|
|
|
|
|
print "Key: $key, Value: ${$hashref}{$key}\n"; |
17
|
|
|
|
|
|
|
} |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $encoded_string = bencode($hashref); |
20
|
|
|
|
|
|
|
print $encoded_string."\n"; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
=head1 DESCRIPTION |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
This module provides two functions, C and C, which |
25
|
|
|
|
|
|
|
encode and decode bencoded strings respectivly. |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head2 Encoding |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
C expects to be passed a single value, which is either a scalar, |
30
|
|
|
|
|
|
|
a arrary ref, or a hash ref, and it returns a scalar containing the bencoded |
31
|
|
|
|
|
|
|
representation of the data structure it was passed. If the value passed was |
32
|
|
|
|
|
|
|
a scalar, it returns either a bencoded string, or a bencoded integer (floating |
33
|
|
|
|
|
|
|
points are not implemented, and would be returned as a string rather than a |
34
|
|
|
|
|
|
|
integer). If the value was a array ref, it returns a bencoded list, with all |
35
|
|
|
|
|
|
|
the values of that array also bencoded recursivly. If the value was a hash ref, |
36
|
|
|
|
|
|
|
it returns a bencoded dictionary (which for all intents and purposes can be |
37
|
|
|
|
|
|
|
thought of as a synonym for hash) containing the recursivly bencoded key and |
38
|
|
|
|
|
|
|
value pairs of the hash. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head2 Decoding |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
C expects to be passed a single scalar containing the bencoded string |
43
|
|
|
|
|
|
|
to be decoded. Its return value will be either a hash ref, a array ref, or a |
44
|
|
|
|
|
|
|
scalar, depending on whether the outer most element of the bencoded string |
45
|
|
|
|
|
|
|
was a dictionary, list, or a string/integer respectivly. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head1 SEE ALSO |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
The description of bencode is part of the bittorrent protocol specification |
50
|
|
|
|
|
|
|
which can be found at http://bitconjurer.org/BitTorrent/protocol.html |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 BUGS |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
No error detection of bencoded data. Damaged input will most likely cause very bad things to happen, up to and including causeing the bdecode function to recurse infintly. |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 AUTHOR & COPYRIGHT |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
Created by R. Kyle Murphy , aka Orclev. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
Copyright 2003 R. Kyle Murphy. All rights reserved. Convert::Bencode |
61
|
|
|
|
|
|
|
is free software; you may redistribute it and/or modify it under the |
62
|
|
|
|
|
|
|
same terms as Perl itself. |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
|
66
|
1
|
|
|
1
|
|
36524
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
67
|
1
|
|
|
1
|
|
4
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
30
|
|
68
|
1
|
|
|
1
|
|
1484
|
use bytes; |
|
1
|
|
|
|
|
15
|
|
|
1
|
|
|
|
|
5
|
|
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
BEGIN { |
71
|
1
|
|
|
1
|
|
32
|
use Exporter (); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
281
|
|
72
|
1
|
|
|
1
|
|
3
|
our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, @EXPORT_FAIL, %EXPORT_TAGS); |
73
|
|
|
|
|
|
|
|
74
|
1
|
|
|
|
|
1
|
$VERSION = 1.03; |
75
|
1
|
|
|
|
|
17
|
@ISA = qw(Exporter); |
76
|
1
|
|
|
|
|
2
|
@EXPORT_OK = qw(&bencode &bdecode); |
77
|
1
|
|
|
|
|
3
|
@EXPORT_FAIL = qw(&_dechunk); |
78
|
1
|
|
|
|
|
53
|
%EXPORT_TAGS = (all => [qw(&bencode &bdecode)]); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
our @EXPORT_OK; |
81
|
|
|
|
|
|
|
|
82
|
1
|
|
|
1
|
|
1000
|
END { } |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub bencode { |
85
|
1
|
|
|
1
|
|
1522
|
no locale; |
|
1
|
|
|
|
|
469
|
|
|
1
|
|
|
|
|
5
|
|
86
|
10
|
|
|
10
|
0
|
4843
|
my $item = shift; |
87
|
10
|
|
|
|
|
13
|
my $line = ''; |
88
|
10
|
100
|
|
|
|
24
|
if(ref($item) eq 'HASH') { |
89
|
1
|
|
|
|
|
3
|
$line = 'd'; |
90
|
1
|
|
|
|
|
3
|
foreach my $key (sort(keys %{$item})) { |
|
1
|
|
|
|
|
325
|
|
91
|
3
|
|
|
|
|
11
|
$line .= bencode($key); |
92
|
3
|
|
|
|
|
6
|
$line .= bencode(${$item}{$key}); |
|
3
|
|
|
|
|
11
|
|
93
|
|
|
|
|
|
|
} |
94
|
1
|
|
|
|
|
2
|
$line .= 'e'; |
95
|
1
|
|
|
|
|
4
|
return $line; |
96
|
|
|
|
|
|
|
} |
97
|
9
|
100
|
|
|
|
18
|
if(ref($item) eq 'ARRAY') { |
98
|
1
|
|
|
|
|
2
|
$line = 'l'; |
99
|
1
|
|
|
|
|
3
|
foreach my $l (@{$item}) { |
|
1
|
|
|
|
|
3
|
|
100
|
3
|
|
|
|
|
10
|
$line .= bencode($l); |
101
|
|
|
|
|
|
|
} |
102
|
1
|
|
|
|
|
2
|
$line .= 'e'; |
103
|
1
|
|
|
|
|
3
|
return $line; |
104
|
|
|
|
|
|
|
} |
105
|
8
|
100
|
|
|
|
26
|
if($item =~ /^\d+$/) { |
106
|
3
|
|
|
|
|
5
|
$line = 'i'; |
107
|
3
|
|
|
|
|
4
|
$line .= $item; |
108
|
3
|
|
|
|
|
4
|
$line .= 'e'; |
109
|
3
|
|
|
|
|
9
|
return $line; |
110
|
|
|
|
|
|
|
} |
111
|
5
|
|
|
|
|
11
|
$line = length($item).":"; |
112
|
5
|
|
|
|
|
6
|
$line .= $item; |
113
|
5
|
|
|
|
|
12
|
return $line; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub bdecode { |
117
|
1
|
|
|
1
|
0
|
9
|
my $string = shift; |
118
|
1
|
|
|
|
|
18
|
my @chunks = split(//, $string); |
119
|
1
|
|
|
|
|
105
|
my $root = _dechunk(\@chunks); |
120
|
1
|
|
|
|
|
5
|
return $root; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub _dechunk { |
124
|
10
|
|
|
10
|
|
15
|
my $chunks = shift; |
125
|
|
|
|
|
|
|
|
126
|
10
|
|
|
|
|
10
|
my $item = shift(@{$chunks}); |
|
10
|
|
|
|
|
18
|
|
127
|
10
|
100
|
|
|
|
23
|
if($item eq 'd') { |
128
|
1
|
|
|
|
|
2
|
$item = shift(@{$chunks}); |
|
1
|
|
|
|
|
3
|
|
129
|
1
|
|
|
|
|
1
|
my %hash; |
130
|
1
|
|
|
|
|
6
|
while($item ne 'e') { |
131
|
3
|
|
|
|
|
4
|
unshift(@{$chunks}, $item); |
|
3
|
|
|
|
|
7
|
|
132
|
3
|
|
|
|
|
9
|
my $key = _dechunk($chunks); |
133
|
3
|
|
|
|
|
8
|
$hash{$key} = _dechunk($chunks); |
134
|
3
|
|
|
|
|
4
|
$item = shift(@{$chunks}); |
|
3
|
|
|
|
|
11
|
|
135
|
|
|
|
|
|
|
} |
136
|
1
|
|
|
|
|
17
|
return \%hash; |
137
|
|
|
|
|
|
|
} |
138
|
9
|
100
|
|
|
|
21
|
if($item eq 'l') { |
139
|
1
|
|
|
|
|
2
|
$item = shift(@{$chunks}); |
|
1
|
|
|
|
|
2
|
|
140
|
1
|
|
|
|
|
1
|
my @list; |
141
|
1
|
|
|
|
|
6
|
while($item ne 'e') { |
142
|
3
|
|
|
|
|
5
|
unshift(@{$chunks}, $item); |
|
3
|
|
|
|
|
6
|
|
143
|
3
|
|
|
|
|
9
|
push(@list, _dechunk($chunks)); |
144
|
3
|
|
|
|
|
4
|
$item = shift(@{$chunks}); |
|
3
|
|
|
|
|
8
|
|
145
|
|
|
|
|
|
|
} |
146
|
1
|
|
|
|
|
4
|
return \@list; |
147
|
|
|
|
|
|
|
} |
148
|
8
|
100
|
|
|
|
21
|
if($item eq 'i') { |
149
|
3
|
|
|
|
|
2
|
my $num; |
150
|
3
|
|
|
|
|
4
|
$item = shift(@{$chunks}); |
|
3
|
|
|
|
|
6
|
|
151
|
3
|
|
|
|
|
8
|
while($item ne 'e') { |
152
|
4
|
|
|
|
|
6
|
$num .= $item; |
153
|
4
|
|
|
|
|
4
|
$item = shift(@{$chunks}); |
|
4
|
|
|
|
|
10
|
|
154
|
|
|
|
|
|
|
} |
155
|
3
|
|
|
|
|
7
|
return $num; |
156
|
|
|
|
|
|
|
} |
157
|
5
|
50
|
|
|
|
16
|
if($item =~ /\d/) { |
158
|
5
|
|
|
|
|
5
|
my $num; |
159
|
5
|
|
|
|
|
15
|
while($item =~ /\d/) { |
160
|
5
|
|
|
|
|
9
|
$num .= $item; |
161
|
5
|
|
|
|
|
72
|
$item = shift(@{$chunks}); |
|
5
|
|
|
|
|
17
|
|
162
|
|
|
|
|
|
|
} |
163
|
5
|
|
|
|
|
6
|
my $line = ''; |
164
|
5
|
|
|
|
|
14
|
for(1 .. $num) { |
165
|
32
|
|
|
|
|
32
|
$line .= shift(@{$chunks}); |
|
32
|
|
|
|
|
145
|
|
166
|
|
|
|
|
|
|
} |
167
|
5
|
|
|
|
|
15
|
return $line; |
168
|
|
|
|
|
|
|
} |
169
|
0
|
|
|
|
|
|
return $chunks; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
1; |