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.003003';
3 1     1   23743 use Carp;
  1         2  
  1         89  
4 1     1   5 use strict; use warnings FATAL => 'all';
  1     1   2  
  1         30  
  1         4  
  1         2  
  1         31  
5              
6 1     1   602 use parent 'Exporter::Tiny';
  1         376  
  1         6  
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 1516 my ($bin, %param) = @_;
26              
27 6   50     20 my $len = bytes::length($bin) || return '';
28 6 100       756 if ($param{pad}) {
29 1         7 $bin .= "\0" x (-$len % 4);
30 1         4 $len = bytes::length($bin);
31             }
32 6 100       199 croak "Expected data padded to 4-byte chunks; got length $len" if $len % 4;
33              
34 5         10 my $chunks = $len / 4;
35 5         49 my @values = unpack "(N)$chunks", $bin;
36            
37 5         6 my $str;
38 5         8 for my $val (@values) {
39 21         83 $str .= $chrs[ ( int($val / $_) ) % 85 ] for @multiples;
40             }
41            
42             $str
43 5         22 }
44              
45             sub decode_z85 {
46 6     6 1 277 my ($txt, %param) = @_;
47 6   50     15 my $len = length $txt || return '';
48              
49 6 100       105 croak "Expected Z85 text in 5-byte chunks; got length $len" if $len % 5;
50              
51 5         5 my @values;
52 5         13 for my $idx (grep {; not($_ % 5) } 0 .. $len) {
  110         161  
53 26         24 my ($val, $cnt) = (0, 0);
54              
55 26         26 for my $mult (@multiples) {
56 110         101 my $chr = substr $txt, ($idx + $cnt), 1;
57 110 100       145 last unless length $chr;
58 105 50       155 croak "Invalid Z85 input; '$chr' not recognized"
59             unless exists $intforchr{$chr};
60 105         98 $val += $intforchr{$chr} * $mult;
61 105         92 ++$cnt;
62             }
63              
64 26         31 push @values, $val;
65             }
66              
67 5         8 my $chunks = $len / 5;
68 5         34 my $ret = pack "(N)$chunks", @values;
69 5 100       14 $ret =~ s/\0{0,3}$// if $param{pad};
70 5         23 $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