| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- #!/usr/bin/perl -w
- package Convert::Bencode;
- =head1 NAME
- Convert::Bencode - Functions for converting to/from bencoded strings
- =head1 SYNOPSIS
- use Convert::Bencode qw(bencode bdecode);
- my $string = "d4:ainti12345e3:key5:value4:type4:teste";
- my $hashref = bdecode($string);
- foreach my $key (keys(%{$hashref})) {
- print "Key: $key, Value: ${$hashref}{$key}\n";
- }
- my $encoded_string = bencode($hashref);
- print $encoded_string."\n";
- =head1 DESCRIPTION
- This module provides two functions, C<bencode> and C<bdecode>, which
- encode and decode bencoded strings respectivly.
- =head2 Encoding
- C<bencode()> expects to be passed a single value, which is either a scalar,
- a arrary ref, or a hash ref, and it returns a scalar containing the bencoded
- representation of the data structure it was passed. If the value passed was
- a scalar, it returns either a bencoded string, or a bencoded integer (floating
- points are not implemented, and would be returned as a string rather than a
- integer). If the value was a array ref, it returns a bencoded list, with all
- the values of that array also bencoded recursivly. If the value was a hash ref,
- it returns a bencoded dictionary (which for all intents and purposes can be
- thought of as a synonym for hash) containing the recursivly bencoded key and
- value pairs of the hash.
- =head2 Decoding
- C<bdecode()> expects to be passed a single scalar containing the bencoded string
- to be decoded. Its return value will be either a hash ref, a array ref, or a
- scalar, depending on whether the outer most element of the bencoded string
- was a dictionary, list, or a string/integer respectivly.
- =head1 SEE ALSO
- The description of bencode is part of the bittorrent protocol specification
- which can be found at http://bitconjurer.org/BitTorrent/protocol.html
- =head1 BUGS
- 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.
- =head1 AUTHOR & COPYRIGHT
- Created by R. Kyle Murphy <orclev@rejectedmaterial.com>, aka Orclev.
- Copyright 2003 R. Kyle Murphy. All rights reserved. Convert::Bencode
- is free software; you may redistribute it and/or modify it under the
- same terms as Perl itself.
- =cut
- use strict;
- use warnings;
- use bytes;
- BEGIN {
- use Exporter ();
- our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, @EXPORT_FAIL, %EXPORT_TAGS);
- $VERSION = 1.03;
- @ISA = qw(Exporter);
- @EXPORT_OK = qw(&bencode &bdecode);
- @EXPORT_FAIL = qw(&_dechunk);
- %EXPORT_TAGS = (all => [qw(&bencode &bdecode)]);
- }
- our @EXPORT_OK;
- END { }
- sub bencode {
- no locale;
- my $item = shift;
- my $line = '';
- if(ref($item) eq 'HASH') {
- $line = 'd';
- foreach my $key (sort(keys %{$item})) {
- $line .= bencode($key);
- $line .= bencode(${$item}{$key});
- }
- $line .= 'e';
- return $line;
- }
- if(ref($item) eq 'ARRAY') {
- $line = 'l';
- foreach my $l (@{$item}) {
- $line .= bencode($l);
- }
- $line .= 'e';
- return $line;
- }
- if($item =~ /^\d+$/) {
- $line = 'i';
- $line .= $item;
- $line .= 'e';
- return $line;
- }
- $line = length($item).":";
- $line .= $item;
- return $line;
- }
- sub bdecode {
- my $string = shift;
- my @chunks = split(//, $string);
- my $root = _dechunk(\@chunks);
- return $root;
- }
- sub _dechunk {
- my $chunks = shift;
- my $item = shift(@{$chunks});
- if($item eq 'd') {
- $item = shift(@{$chunks});
- my %hash;
- while($item ne 'e') {
- unshift(@{$chunks}, $item);
- my $key = _dechunk($chunks);
- $hash{$key} = _dechunk($chunks);
- $item = shift(@{$chunks});
- }
- return \%hash;
- }
- if($item eq 'l') {
- $item = shift(@{$chunks});
- my @list;
- while($item ne 'e') {
- unshift(@{$chunks}, $item);
- push(@list, _dechunk($chunks));
- $item = shift(@{$chunks});
- }
- return \@list;
- }
- if($item eq 'i') {
- my $num;
- $item = shift(@{$chunks});
- while($item ne 'e') {
- $num .= $item;
- $item = shift(@{$chunks});
- }
- return $num;
- }
- if($item =~ /\d/) {
- my $num;
- while($item =~ /\d/) {
- $num .= $item;
- $item = shift(@{$chunks});
- }
- my $line = '';
- for(1 .. $num) {
- $line .= shift(@{$chunks});
- }
- return $line;
- }
- return $chunks;
- }
- 1;
|