#! /usr/bin/perl -w # # A self-contained bdecoder, cut'n'pasted together from various sources # (largely CPAN) on the web. Use at your own risk. --cpk # use strict; use warnings; use bytes; my %Printable = ( ( map { chr($_), unpack('H2', chr($_)) } (0..255) ), "\\"=>'\\', "\r"=>'r', "\n"=>'n', "\t"=>'t', "\""=>'"' ); sub printable ($) { local $_ = ( defined $_[0] ? $_[0] : '' ); s/([\r\n\t\"\\\x00-\x1f\x7F-\xFF])/\\$Printable{$1}/sg; return $_; } 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; } sub print_array { my ($data, $indent) = @_; my $i = 0; print ' ' x $indent; print "a:\n"; foreach my $el (@$data) { print " " x ($indent + 2); print "$i:\n"; if (ref($el) eq 'ARRAY') { print_array($el, $indent + 4); } elsif (ref($el) eq 'HASH') { print_dict($el, $indent + 4); } else { print_scalar($el, $indent + 4); } $i += 1; } } sub print_dict { my ($data, $indent) = @_; my ($key, $el); print ' ' x $indent; print "d:\n"; while ( ($key, $el) = each(%$data)) { $key = printable($key); print " " x ($indent + 2); print "$key:\n"; if (ref($el) eq 'ARRAY') { print_array($el, $indent + 4); } elsif (ref($el) eq 'HASH') { print_dict($el, $indent + 4); } else { print_scalar($el, $indent + 4); } } } sub print_scalar { my ($data, $indent) = @_; my $cropped = ""; my $esc_data = printable($data); if (length($esc_data) > 500) { $esc_data = substr($esc_data, 0, 500); $cropped = "[...]"; } print ' ' x $indent; print "s: $esc_data$cropped\n"; } sub read_file { my ($file) = @_; local($/) = wantarray ? $/ : undef; local(*F); my $r; my (@r); open(F, "<$file") || return undef; @r = ; close(F) || return undef; return $r[0] unless wantarray; return @r; } # Take each command line argument as a filename, # read it, and try to dump out bdecoded version. # foreach my $arg (@ARGV) { my $raw = read_file($arg); unless ($raw) { print "Could not open $arg, skipping.\n"; next; } my $data = bdecode($raw); unless ($data) { print "Could not decode data in $arg\n"; next; } if (ref($data) eq 'ARRAY') { print_array($data, 1); } elsif (ref($data) eq 'HASH') { print_dict($data, 1); } else { print_scalar($data, 1); } }