1
0

Bencode.pm 4.0 KB

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