File Coverage

blib/lib/Convert/zBase32.pm
Criterion Covered Total %
statement 52 61 85.2
branch 8 12 66.6
condition n/a
subroutine 7 9 77.7
pod 4 4 100.0
total 71 86 82.5


line stmt bran cond sub pod time code
1             package Convert::zBase32;
2              
3 1     1   20646 use 5.006;
  1         3  
  1         29  
4 1     1   4 use strict;
  1         2  
  1         32  
5 1     1   5 use warnings;
  1         1  
  1         849  
6              
7             require Exporter;
8              
9             our @ISA = qw(Exporter);
10              
11             our %EXPORT_TAGS = ( 'all' => [ qw(
12             encode_zbase32 decode_zbase32 encode_base32 decode_base32
13             ) ] );
14              
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16              
17             our @EXPORT = qw( encode_zbase32 decode_zbase32 );
18              
19             our $VERSION = '0.0201';
20             $VERSION = eval $VERSION;
21              
22             our @zBASE32 = qw( y b n d r f g 8 e j k m c p q x
23             o t 1 u w i s z a 3 4 5 h 7 6 9 );
24             my $q=0;
25             our %zB2N = map { $_ => $q++ } @zBASE32;
26              
27             our @BASE32 = qw( a b c d e f g h i j k l m n o p
28             q r s t u v w x y z 2 3 4 5 6 7 );
29             $q=0;
30             our %B2N = map { $_ => $q++ } @BASE32;
31              
32             # masks to use if the begining of 5-bit is w/in this octet
33             # keyed on the position w/in the octet
34             my @masks = ( 0x1f, 0x3e, 0x7c, 0xf8, # all 5 bits in the octet
35             0xf0, 0xe0, 0xc0, 0x80 # into the next one
36             );
37              
38             # masks of up to 4 bits in the next octet
39             # keyed on the sub offset
40             my @more_masks = ( 0x1, 0x3, 0x7, 0xf );
41              
42             ##################################################################
43             sub encode_zbase32
44             {
45 4     4 1 2258 my( $string ) = @_;
46              
47 4         7 my $ret;
48 4         11 foreach my $part ( _split_string( $string ) ) {
49 61 50       88 die "There is no $part" unless $part < 32;
50 61         74 $ret .= $zBASE32[ $part ];
51             }
52 4         12 return $ret;
53             }
54              
55             ##################################################################
56             sub decode_zbase32
57             {
58 8     8 1 3954 my( $string ) = @_;
59 8         44 return _join_string( map { $zB2N{$_} } split '', lc $string );
  122         388  
60             }
61              
62              
63             ##################################################################
64             sub encode_base32
65             {
66 0     0 1 0 my( $string ) = @_;
67              
68 0         0 my $ret;
69 0         0 foreach my $part ( _split_string( $string ) ) {
70 0 0       0 die "There is no $part" unless $part < 32;
71 0         0 $ret .= $BASE32[ $part ];
72             }
73 0         0 return $ret;
74             }
75              
76             ##################################################################
77             sub decode_base32
78             {
79 0     0 1 0 my( $string ) = @_;
80 0         0 return _join_string( map { $B2N{$_} } split '', lc $string );
  0         0  
81             }
82              
83              
84             ##################################################################
85             sub _split_string
86             {
87 14     14   5799 my( $string ) = @_;
88 14         30 my $len = 8 * length $string;
89 14         19 my( @output, $chunk, $part, $offset, $suboffset );
90             # we want to build an array of 5 bit numbers
91 14         36 foreach( my $q=0; $q < $len ; $q+=5 ) {
92 131         166 $offset = int $q / 8;
93 131         127 $suboffset = $q % 8;
94             # warn "$offset, $suboffset";
95             # first part
96 131         175 $part = ord substr $string, $offset, 1;
97             # lower bits
98 131         149 $chunk = ( $part & $masks[ $suboffset ] ) >> $suboffset;
99             # is this all we need?
100 131         144 $suboffset -= 4;
101 131 100       207 if( $suboffset >= 0 ) {
102             # next part
103 71 100       98 if( $q + 5 > $len ) {
104 14         18 $part = 0; # past the end
105             }
106             else {
107 57         65 $part = ord substr $string, $offset+1, 1;
108             }
109 71         88 $chunk |= ( $part & $more_masks[ $suboffset ] )
110             << (4- $suboffset);
111             }
112 131         271 push @output, $chunk;
113             }
114 14         55 return @output;
115             }
116              
117             ##################################################################
118             sub _join_string
119             {
120 15     15   5364 my( @output ) = @_;
121 15         29 my $len = 5 * @output;
122 15         50 my @ret = (0) x int( $len / 8);
123              
124 15         42 my $n = 0;
125 15         17 my( $offset, $suboffset, $part, $chunk );
126 15         39 foreach( my $q=0; $q < $len ; $q+=5 ) {
127 171         167 $offset = int $q / 8;
128 171         174 $suboffset = $q % 8;
129              
130             # warn "$offset, $suboffset";
131             # first part
132 171         153 $part = $output[ $n ];
133             # lower bits
134 171         167 $chunk = ($part << $suboffset ) & $masks[ $suboffset ];
135 171         141 $ret[ $offset ] |= $chunk;
136              
137             # is this all we needed?
138 171         157 $suboffset -= 4;
139 171 100       297 if( $suboffset >= 0 ) {
140 90         119 $ret[ $offset +1 ] |=
141             ( $part >> (4-$suboffset) ) & $more_masks[ $suboffset ];
142             }
143 171         332 $n++;
144             }
145 15         100 my $ret = join '', map chr, @ret;
146             # remove any padding...
147 15 50       57 substr( $ret, -1, 1, '' ) if 0 == ord substr( $ret, -1 );
148 15         53 return $ret;
149             }
150              
151              
152             ##################################################################
153              
154              
155             1;
156             __END__