File Coverage

blib/lib/Convert/Z85.pm
Criterion Covered Total %
statement 42 42 100.0
branch 11 12 91.6
condition 2 4 50.0
subroutine 6 6 100.0
pod 2 2 100.0
total 63 66 95.4


line stmt bran cond sub pod time code
1             package Convert::Z85;
2             $Convert::Z85::VERSION = '0.004002';
3 1     1   14173 use Carp;
  1         2  
  1         66  
4 1     1   4 use strict; use warnings FATAL => 'all';
  1     1   1  
  1         24  
  1         3  
  1         1  
  1         24  
5              
6 1     1   395 use parent 'Exporter::Tiny';
  1         236  
  1         3  
7             our @EXPORT = our @EXPORT_OK = qw/
8             encode_z85
9             decode_z85
10             /;
11              
12             require bytes;
13              
14             my @chrs = split '',
15             '0123456789abcdefghijklmnopqrstuvwxyz'
16             .'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
17             .'.-:+=^!/*?&<>()[]{}@%$#'
18             ;
19              
20             my %intforchr = map {; $chrs[$_] => $_ } 0 .. $#chrs;
21              
22             my @multiples = reverse map {; 85 ** $_ } 0 .. 4;
23              
24             sub encode_z85 {
25 6     6 1 2016 my ($bin, %param) = @_;
26              
27 6   50     16 my $len = bytes::length($bin) || return '';
28 6 100       683 if ($param{pad}) {
29 1         4 $bin .= "\0" x (-$len % 4);
30 1         2 $len = bytes::length($bin);
31             }
32 6 100       188 croak "Expected data padded to 4-byte chunks; got length $len" if $len % 4;
33              
34 5         7 my $chunks = $len / 4;
35 5         41 my @values = unpack "(N)$chunks", $bin;
36            
37 5         5 my $str;
38 5         7 for my $val (@values) {
39 21         80 $str .= $chrs[ ( int($val / $_) ) % 85 ] for @multiples;
40             }
41            
42             $str
43 5         22 }
44              
45             sub decode_z85 {
46 6     6 1 392 my ($txt, %param) = @_;
47 6   50     13 my $len = length $txt || return '';
48              
49 6 100       108 croak "Expected Z85 text in 5-byte chunks; got length $len" if $len % 5;
50              
51 5         5 my @values;
52 5         11 for my $idx (grep {; not($_ % 5) } 0 .. $len) {
  110         109  
53 26         17 my ($val, $cnt) = (0, 0);
54              
55 26         24 for my $mult (@multiples) {
56 110         84 my $chr = substr $txt, ($idx + $cnt), 1;
57 110 100       158 last unless length $chr;
58 105 50       129 croak "Invalid Z85 input; '$chr' not recognized"
59             unless exists $intforchr{$chr};
60 105         100 $val += $intforchr{$chr} * $mult;
61 105         93 ++$cnt;
62             }
63              
64 26         28 push @values, $val;
65             }
66              
67 5         9 my $chunks = $len / 5;
68 5         31 my $ret = pack "(N)$chunks", @values;
69 5 100       14 $ret =~ s/\0{0,3}$// if $param{pad};
70 5         18 $ret
71             }
72              
73              
74             1;
75              
76             =pod
77              
78             =head1 NAME
79              
80             Convert::Z85 - Encode and decode Z85 strings
81              
82             =head1 SYNOPSIS
83              
84             use Convert::Z85;
85              
86             my $encoded = encode_z85($binarydata);
87             my $decoded = decode_z85($encoded);
88              
89             =head1 DESCRIPTION
90              
91             An implementation of the I encoding scheme (as described in
92             L) for encoding binary data as
93             plain text.
94              
95             Modelled on the L implementation.
96              
97             This module uses L to export two functions by default:
98             L and L.
99              
100             =head2 encode_z85
101              
102             my $z85 = encode_z85($data);
103              
104             Takes binary data in 4-byte chunks and returns a Z85-encoded text string.
105              
106             Per the spec, padding is not performed automatically; the B option can be
107             specified to pad data with trailing zero bytes:
108              
109             my $z85 = encode_z85($data, pad => 1);
110              
111             =head2 decode_z85
112              
113             my $bin = decode_z85($encoded);
114              
115             Takes a Z85 text string and returns the original binary data.
116              
117             Throws a stack trace if invalid data is encountered.
118              
119             Per the spec, removing padding is not performed automatically; the B
120             option can be specified to remove trailing zero bytes:
121              
122             my $bin = decode_z85($encoded, pad => 1);
123              
124             =head1 SEE ALSO
125              
126             L
127              
128             L
129              
130             L
131              
132             =head1 AUTHOR
133              
134             Jon Portnoy
135              
136             =cut