File Coverage

blib/lib/Convert/Bencode.pm
Criterion Covered Total %
statement 98 99 98.9
branch 13 14 92.8
condition n/a
subroutine 10 10 100.0
pod 0 2 0.0
total 121 125 96.8


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;