File Coverage

blib/lib/Convert/Base81.pm
Criterion Covered Total %
statement 170 186 91.4
branch 24 34 70.5
condition 0 3 0.0
subroutine 15 16 93.7
pod 10 10 100.0
total 219 249 87.9


line stmt bran cond sub pod time code
1             package Convert::Base81;
2              
3 8     8   471753 use 5.016001;
  8         85  
4 8     8   44 use warnings;
  8         15  
  8         204  
5 8     8   77 use strict;
  8         16  
  8         195  
6              
7 8     8   40 use Carp;
  8         23  
  8         687  
8 8         828 use Math::Int128 qw(uint128 uint128_to_number
9 8     8   3819 uint128_add uint128_divmod uint128_left uint128_mul);
  8         58246  
10              
11             #use Smart::Comments q(###);
12              
13             our $VERSION = '1.01';
14              
15 8     8   61 use Exporter qw(import);
  8         16  
  8         20384  
16              
17             our %EXPORT_TAGS = (
18             pack => [ qw(b3_pack81 b9_pack81 b27_pack81) ],
19             unpack => [ qw(b3_unpack81 b9_unpack81 b27_unpack81) ],
20             );
21              
22             our @EXPORT_OK = (
23             qw(base81_check base81_encode base81_decode rwsize),
24             @{ $EXPORT_TAGS{pack} },
25             @{ $EXPORT_TAGS{unpack} },
26             );
27              
28             #
29             # Add an :all tag automatically.
30             #
31             $EXPORT_TAGS{all} = [@EXPORT_OK];
32              
33             =head1 NAME
34              
35             Convert::Base81 - Encoding and decoding to and from Base 81 strings
36              
37             =head1 SYNOPSIS
38              
39             use Convert::Base81;
40            
41             my $encoded = Convert::Base81::encode($data);
42             my $decoded = Convert::Base81::decode($encoded);
43              
44             or
45              
46             use Convert::Base81 qw(base81_encode base81_decode);
47            
48             my $encoded = base81_encode($data);
49             my $decoded = base81_decode($encoded);
50              
51             =head1 DESCRIPTION
52              
53             This module implements a I conversion for encoding binary
54             data as text. This is done by interpreting each group of fifteen bytes
55             as a 120-bit integer, which is then converted to a seventeen-digit base 81
56             representation using the alphanumeric characters 0-9, A-Z, and a-z, in
57             addition to the punctuation characters !, #, $, %, (, ), *,
58             +, -, ;, =, ?, @, ^, _, {, |, }, and ~, in that order, characters that
59             are safe to use in JSON and XML formats.
60              
61             This creates a string that is (1.2666) larger than the original
62             data, making it more efficient than L's 3-to-4 ratio (1.3333)
63             but slightly less so than the efficiency of L's 4-to-5 ratio (1.25).
64              
65             It does have the advantage of a natural ternary system: if your data is
66             composed of only three, or nine, or twenty-seven distinct values, its
67             size can be compressed instead of expanded, and this module has functions
68             that will do that.
69              
70             use Convert::Base81 qw(b3_pack81 b3_unpack81);
71              
72             my $input_string = q(rrgrbgggggrrgbrrbbbbrbrgggrggggg);
73             my $b81str = b3_pack81("rgb", $input_string);
74              
75             The returned string will be one-fourth the size of the original. Equivalent
76             functions exist for 9-digit and 27-digit values, which will return strings
77             one-half and three-fourths the size of the original, respectively.
78              
79             =cut
80              
81             #
82             # character value
83             # 0..9: 0..9
84             # A..Z: 10..35
85             # a..z: 36..61
86             # punc: 62..80
87             #
88             # Or, in a 9x9 tabular form, displaying the trits (0, 1, -):
89             #
90             # | 0 1 2 3 4 5 6 7 8
91             # +-------------------------------------------------------------
92             # ('0'..'8') 0 | 0000 0001 000- 0010 0011 001- 00-0 00-1 00--
93             # ('9'..'H') 9 | 0100 0101 010- 0110 0111 011- 01-0 01-1 01--
94             # ('I'..'Q') 18 | 0-00 0-01 0-0- 0-10 0-11 0-1- 0--0 0--1 0---
95             # ('R'..'Z') 27 | 1000 1001 100- 1010 1011 101- 10-0 10-1 10--
96             # ('a'..'i') 36 | 1100 1101 110- 1110 1111 111- 11-0 11-1 11--
97             # ('j'..'r') 45 | 1-00 1-01 1-0- 1-10 1-11 1-1- 1--0 1--1 1---
98             # ('s'..'!') 54 | -000 -001 -00- -010 -011 -01- -0-0 -0-1 -0--
99             # ('#'..';') 63 | -100 -101 -10- -110 -111 -11- -1-0 -1-1 -1--
100             # ('='..'~') 72 | --00 --01 --0- --10 --11 --1- ---0 ---1 ----
101             #
102             #
103             # Take a number from 0 to 80, and turn it into a character.
104             #
105              
106             my @b81_encode = ('0' .. '9', 'A' .. 'Z', 'a' .. 'z',
107             '!', '#', '$', '%', '(', ')', '*', '+', '-', ';',
108             '=', '?', '@', '^', '_', '{', '|', '}', '~');
109              
110              
111             my @b81_decode = (
112             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
113             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
114             -1, 62, -1, 63, 64, 65, -1, -1, 66, 67, 68, 69, -1, 70, -1, -1,
115             0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 71, -1, 72, -1, 73,
116             74, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
117             25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, 75, 76,
118             -1, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
119             51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 78, 79, 80, -1,
120             );
121              
122             my %rwsizes = (I128 => [15, 19], I64 => [7, 9]);
123             my $rwkey = "I128";
124              
125             =head1 FUNCTIONS
126              
127             =head3 base81_check
128              
129             Examine a string for characters that fall outside the Base 81 character set.
130              
131             Returns the first character position that fails the test, or -1 if no characters fail.
132              
133             if (my $d = base81_check($base81str) != -1)
134             {
135             carp "Incorrect character at position $d; cannot decode input string";
136             return undef;
137             }
138              
139             =cut
140              
141             sub base81_check
142             {
143 0     0 1 0 my($str) = @_;
144 0         0 my(@chars) = split(//, $str);
145              
146             #
147             ### Check validity of: $str
148             ### Which becomes array: @chars
149             #
150 0         0 for my $j (0 .. $#chars)
151             {
152 0         0 my $o = ord($chars[$j]);
153 0 0 0     0 return $j if ($o > 0x7f or $b81_decode[$o] == -1);
154             }
155 0         0 return -1;
156             }
157              
158             =head3 base81_encode
159              
160             =head3 Convert::Base81::encode
161              
162             Converts input data to Base81 test.
163              
164             This function may be exported as C into the caller's namespace.
165              
166             my $datalen = length($data);
167             my $encoded = base81_encode($data);
168              
169             Or, if you want to have managable lines, read 45 bytes at a time and
170             write 57-character lines (remembering that C takes 15 bytes
171             at a time and encodes to 19 bytes). Remember to save the original length
172             in case the data had to be padded out to a multiple of 15.
173              
174             =cut
175              
176             sub encode
177             {
178 10     10 1 2766 my($plain) = @_;
179 10         31 my @mlist;
180 10         23 my($readsize, $writesize) = rwsize();
181 10         37 my $imod = uint128(81);
182 10         38 my $rem = uint128();
183              
184             #
185             # Extra zero bytes to bring the length up to the read size.
186             #
187 10         22 my $extra = -length($plain) % $readsize;
188 10         23 $plain .= "\0" x $extra;
189              
190 10         53 for my $str7 (unpack "(a${readsize})*", $plain)
191             {
192 44         90 my $ptotal = uint128(0);
193 44         97 my @tmplist = (0) x $writesize;
194              
195             #
196             # Calculate $ptotal = ($ptotal << 8) + $c;
197             #
198 44         118 for my $c (unpack('C*', $str7))
199             {
200 524         1001 uint128_left($ptotal, $ptotal, 8);
201 524         1107 uint128_add($ptotal, $ptotal, uint128($c));
202             }
203              
204             #
205             ### rtotal: "$ptotal"
206             #
207             # Calculate the mod 81 list.
208             #
209 44         92 for my $j (reverse 0 .. $writesize - 1)
210             {
211 666         1204 uint128_divmod($ptotal, $rem, $ptotal, $imod);
212 666         1006 $tmplist[$j] = uint128_to_number($rem);
213             }
214              
215 44         145 push @mlist, @tmplist;
216             }
217              
218 10         23 return join "", map{$b81_encode[$_]} @mlist;
  666         1045  
219             }
220              
221             *base81_encode = \&encode;
222              
223             =head3 base81_decode
224              
225             =head3 Convert::Base81::decode
226              
227             Converts the Base81-encoded string back to bytes. Any spaces, linebreaks, or
228             other whitespace are stripped from the string before decoding.
229              
230             This function may be exported as C into the caller's namespace.
231              
232             If your original data wasn't an even multiple of fifteen in length, the
233             decoded data will have some padding with null bytes ('\0'), which can be removed.
234              
235             #
236             # Decode the string and compare its length with the length of the original data.
237             #
238             my $decoded = base81_decode($data);
239             my $padding = length($decoded) - $datalen;
240             chop $decoded while ($padding-- > 0);
241              
242             =cut
243              
244             sub decode
245             {
246 10     10 1 3480 my($encoded) = @_;
247 10         23 my($readsize, $writesize) = rwsize();
248 10         31 my $imul = uint128(81);
249 10         35 my $rem = uint128();
250              
251 10         24 $encoded =~ tr[ \t\r\n\f][]d;
252              
253 10         21 my $extra = -length($encoded) % $writesize;
254 10 50       25 $encoded .= '0' x $extra if ($extra != 0);
255              
256 10         12 my @mlist;
257              
258 10         49 for my $str9 (unpack "(a${writesize})*", $encoded)
259             {
260 44         88 my $etotal = uint128(0);
261 44         117 my @tmplist = (q(0)) x $readsize;
262              
263 44         95 for my $c (unpack('C*', $str9))
264             {
265 666         1173 my $iadd = uint128($b81_decode[$c]);
266 666         1221 uint128_mul($etotal, $etotal, $imul);
267 666         1193 uint128_add($etotal, $etotal, $iadd);
268             }
269              
270             #
271             ### Read string: $str9
272             ### total = sprintf("0x%0x", $etotal)
273             #
274 44         97 for my $j (reverse 0 .. $readsize - 1)
275             {
276 524         1220 uint128_divmod($etotal, $rem, $etotal, uint128(256));
277 524         992 $tmplist[$j] = uint128_to_number($rem);
278             }
279 44         165 push @mlist, @tmplist;
280             }
281              
282 10         24 return join "", map{chr($_)} @mlist;
  524         875  
283             }
284              
285             *base81_decode = \&decode;
286              
287             =head3 rwsize
288              
289             By default, the C function reads 15 bytes, and writes 19,
290             resulting in an expansion ratio of 1.2666. It does require 128-bit
291             integers to calculate this, which is simulated in a library. If your
292             decoding destination doesn't have a library available, the encode
293             function can be reduced to reading 7 bytes and writing 9, giving an
294             expansion ratio of 1.2857. This only requires 64-bit integers, which
295             many environments can handle.
296              
297             Note that this does not affect the operation of this module, which
298             will use 128-bit integers regardless.
299              
300             To set the smaller size, use:
301              
302             my($readsize, $writesize) = rwsize("I64");
303              
304             To set it back:
305              
306             my($readsize, $writesize) = rwsize("I128");
307              
308             To simply find out the current read/write sizes:
309              
310             my($readsize, $writesize) = rwsize();
311              
312             Obviously, if you use the smaller sized encoding, you need to
313             send that information along with the encoded data.
314              
315             =cut
316              
317             sub rwsize
318             {
319 21 100   21 1 174 if (scalar @_ > 0)
320             {
321 1         3 my $key = $_[0];
322              
323 1 50       4 if (exists $rwsizes{$key})
324             {
325 1         3 $rwkey = $key;
326             }
327             else
328             {
329 0         0 carp "Unknown key '$key'";
330             }
331             }
332              
333 21         28 return @{$rwsizes{$rwkey}};
  21         58  
334             }
335              
336             =head2 the 'pack' tag
337              
338             If your data falls into a domain of 3, 9, or 27 characters, then the Base81
339             format can compress your data to 1/4, 1/2, or 3/4, of its original size.
340              
341             =head3 b3_pack81
342              
343             $three_chars = "01-";
344              
345             b3_pack81($three_chars, $inputstring);
346              
347             or
348              
349             b3_pack81($three_chars, \@inputarray);
350              
351             Transform a string (or array) consisting of three and only three
352             characters into a Base 81 string.
353              
354             $packedstr = b3_pack81("01-", "01-0-1011000---1");
355              
356             or
357              
358             $packedstr = b3_pack81("01-", [qw(0 1 - 0 - 1 0 1 1 0 0 0 - - - 1)]);
359              
360             =cut
361              
362             sub b3_pack81
363             {
364 12     12 1 3507 my($c3, $data) = @_;
365 12         22 my @blist;
366              
367             #
368             # Set up the conversion hash and convert the column list
369             # into two-bit values.
370             #
371 12         66 my $ctr = 0;
372 12         55 my %convert3 = map{ $_ => $ctr++} split //, $c3;
  36         95  
373              
374 12 50       42 if (ref $data eq 'ARRAY')
375             {
376 0         0 @blist = map{$convert3{$_}} @{ $data };
  0         0  
  0         0  
377             }
378             else
379             {
380 12         36 @blist = map{$convert3{$_}} split //, $data;
  118         206  
381             }
382              
383 12         53 push @blist, (substr $c3, 0, 1) x (-scalar(@blist) % 4);
384              
385 12         20 my $str = "";
386              
387 12         39 for my $j (1 .. scalar(@blist) >> 2)
388             {
389 32         63 my($z, $y, $x, $w) = splice(@blist, 0, 4);
390 32         83 $str .= $b81_encode[27*$z + 9*$y + 3*$x + $w];
391             }
392              
393 12         43 return $str;
394             }
395              
396             =head3 b9_pack81
397              
398             b9_pack81("012345678", $inputstring);
399              
400             or
401              
402             b9_pack81("012345678", \@inputarray);
403              
404             Transform a string (or array) consisting of up to nine
405             characters into a Base 81 string.
406              
407             $packedstr = b9_pack81("012345678", "6354822345507611");
408              
409             or
410              
411             $packedstr = b9_pack81("012345678", [qw(6 3 5 4 8 2 2 3 4 5 5 0 7 6 1 1)]);
412              
413             =cut
414              
415             sub b9_pack81
416             {
417 8     8 1 2224 my($c9, $data) = @_;
418 8         15 my @blist;
419              
420             #
421             # Set up the conversion hash and collect the input data.
422             #
423 8         12 my $ctr = 0;
424 8         33 my %x9 = map{ $_ => $ctr++} split //, $c9;
  72         148  
425              
426 8 50       35 if (ref $data eq 'ARRAY')
427             {
428 0         0 @blist = map{$x9{$_}} @{ $data };
  0         0  
  0         0  
429             }
430             else
431             {
432 8         21 @blist = map{$x9{$_}} split //, $data;
  50         111  
433             }
434              
435             #
436             ### Input data: @blist
437             #
438             # Pad by a zero character if the data length is odd.
439             #
440 8 100       34 push @blist, substr $c9, 0, 1 if (scalar(@blist) % 2);
441              
442 8         17 my $str = "";
443              
444 8         27 for my $j (1 .. scalar(@blist) >> 1)
445             {
446 26         49 my($z, $y) = splice(@blist, 0, 2);
447 26         55 $str .= $b81_encode[9*$z + $y];
448             }
449              
450 8         30 return $str;
451             }
452              
453             =head3 b27_pack81
454              
455             b27_pack81($twenty7_chars, $inputstring);
456              
457             or
458              
459             b27_pack81($twenty7_chars, \@inputarray);
460              
461             Transform a string (or array) consisting of up to twenty-seven
462             characters into a Base 81 string.
463              
464             $base27str = join("", ('a' .. 'z', '_'));
465             $packedstr = b27_pack81($base27str, "anxlfqunxpkswqmei_qh_zkr");
466              
467             or
468              
469             $packedstr = b27_pack81($base27str, [qw(a n x l f q u n x p k s w q m e i _ q h _ z k r)]);
470              
471             =cut
472              
473             sub b27_pack81
474             {
475 8     8 1 2145 my($c27, $data) = @_;
476 8         17 my @blist;
477             my @clist;
478              
479             #
480             # Set up the conversion hash and collect the input data.
481             ### b27_pack81 input data: $data
482             #
483 8         11 my $ctr = 0;
484 8         43 my %x27 = map{ $_ => $ctr++} split //, $c27;
  216         410  
485              
486 8 50       48 if (ref $data eq 'ARRAY')
487             {
488 0         0 @blist = map{$x27{$_}} @{ $data };
  0         0  
  0         0  
489             }
490             else
491             {
492 8         24 @blist = map{$x27{$_}} split //, $data;
  69         122  
493             }
494              
495             #
496             ### Input data: @blist
497             #
498             # Save any leftover characters in advance of taking four at a time.
499             #
500 8         32 my @tail = splice(@blist, scalar @blist - scalar(@blist) % 4);
501              
502             #
503             # z0 y0 z1 y1 z2 y2 z3 y3
504             # |ooo p|pp qq|q rrr|sss t|tt uu|u vvv|
505             # | | | | | | |
506             #
507             #
508             # Take in four base-27 characters, write out three base-81 characters.
509             #
510 8         29 while (my(@x4) = splice(@blist, 0, 4))
511             {
512 14         28 my $x = 19683 * $x4[0] + 729 * $x4[1] + 27 * $x4[2] + $x4[3];
513 14         19 my @mods;
514              
515 14         24 for (1 .. 3)
516             {
517 42         96 unshift @mods, $b81_encode[$x % 81];
518 42         66 $x = int $x/81;
519             }
520              
521 14         49 push @clist, @mods;
522             }
523              
524             #
525             ### Remaining portion of input: @tail
526             #
527 8 100       20 if (scalar @tail)
528             {
529 6         12 my $x = $tail[0] * 3;
530              
531 6 100       17 if (scalar @tail == 2)
532             {
533 3         9 $x += $tail[1]/9;
534 3         7 push @clist, $b81_encode[$x];
535 3         8 $x = ($tail[1] % 9) * 9;
536             }
537              
538 6 100       16 if (scalar @tail == 3)
539             {
540 2         5 $x += $tail[1]/9;
541 2         5 push @clist, $b81_encode[$x];
542 2         5 $x = (($tail[1] % 9) * 9) + $tail[2]/3;
543 2         4 push @clist, $b81_encode[$x];
544 2         2 $x = $tail[2] % 3;
545             }
546 6 100       19 push @clist, $b81_encode[$x] if ($x != 0);
547             }
548              
549 8         52 return join "", @clist;
550             }
551              
552             =head2 the 'unpack' tag
553              
554             Naturally, data packed must needs be unpacked, and the following three functions
555             perform that duty.
556              
557             =head3 b3_unpack81
558              
559             Transform a Base81 string back into a string (or array) using
560             only three characters.
561              
562             $data = b3_unpack81("012", "d$+qxW?q");
563              
564             or
565              
566             @array = b3_unpack81("012", "d$+qxW?q");
567              
568             =cut
569              
570             sub b3_unpack81
571             {
572 7     7 1 2197 my($c3, $base81str) = @_;
573              
574 7         15 $base81str =~ tr[ \t\r\n\f][]d;
575              
576 7         24 my @char81 = split(//, $base81str);
577 7         16 my @val81 = map{$b81_decode[ord($_)]} @char81;
  25         60  
578              
579             #
580             # Set up the conversion array on the fly.
581             #
582 7         17 my(@convert3) = split(//, $c3);
583 7         8 my @clist;
584              
585 7         14 for my $x (@val81)
586             {
587 25         54 push @clist, $convert3[int($x/27)];
588 25         51 push @clist, $convert3[int(($x % 27)/9)];
589 25         42 push @clist, $convert3[int(($x % 9)/3)];
590 25         45 push @clist, $convert3[$x % 3];
591             }
592              
593 7 50       41 return wantarray? @clist: join "", @clist;
594             }
595              
596             =head3 b9_unpack81
597              
598             Transform a Base81 string back into a string (or array) using
599             only nine characters.
600              
601             $nine_chars = join "", ('0' .. '8'');
602              
603             $data = b27_unpack81($nine_chars, "d$+qxW?q");
604              
605             or
606              
607             @array = b27_unpack81($nine_chars, "d$+qxW?q");
608              
609             =cut
610              
611             sub b9_unpack81
612             {
613 6     6 1 2002 my($c9, $base81str) = @_;
614              
615 6         13 $base81str =~ tr[ \t\r\n\f][]d;
616              
617 6         21 my @char81 = split(//, $base81str);
618 6         13 my @val81 = map{$b81_decode[ord($_)]} @char81;
  22         43  
619              
620             #
621             # Set up the conversion array on the fly because
622             # the don't-care character is changeable.
623             #
624 6         19 my(@x9) = split(//, $c9);
625 6         9 my @clist;
626              
627 6         13 for my $x (@val81)
628             {
629 22         48 push @clist, $x9[int($x/9)];
630 22         45 push @clist, $x9[$x % 9];
631             }
632              
633 6 50       36 return wantarray? @clist: join "", @clist;
634             }
635              
636              
637             =head3 b27_unpack81
638              
639             Transform a Base81 string back into a string (or array) using
640             only twenty seven characters.
641              
642             $twenty7_chars = join("", ('a' .. 'z', '&'));
643              
644             $data = b27_unpack81($twenty7_chars, "d$+qxW?q");
645              
646             or
647              
648             @array = b27_unpack81($twenty7_chars, "d$+qxW?q");
649              
650             =cut
651              
652             sub b27_unpack81
653             {
654 6     6 1 2018 my($c27, $base81str) = @_;
655              
656 6         14 $base81str =~ tr[ \t\r\n\f][]d;
657              
658 6         22 my @char81 = split(//, $base81str);
659 6         15 my @val81 = map{$b81_decode[ord($_)]} @char81;
  48         78  
660 6         17 my @tail = splice(@val81, scalar @val81 - scalar(@val81) % 3);
661              
662 6         27 my(@x27) = split(//, $c27);
663 6         11 my @clist;
664              
665             #
666             # Take in 3 base-81 characters, write out four base-27 characters.
667             #
668 6         19 while (my(@x3) = splice(@val81, 0, 3))
669             {
670 14         21 my $x = 6561 * $x3[0] + 81 * $x3[1] + $x3[2];
671 14         20 my @mods;
672              
673 14         23 for (1 .. 4)
674             {
675 56         97 unshift @mods, $x27[$x % 27];
676 56         85 $x = int $x/27;
677             }
678              
679 14         53 push @clist, @mods;
680             }
681              
682 6 100       14 if (scalar @tail)
683             {
684 4         7 my $x = $tail[0];
685 4         10 push @clist, $x27[int $x/3];
686 4         8 $x = ($x % 3) * 9;
687              
688 4 100       9 if (scalar @tail == 2)
689             {
690 2         4 $x += int $tail[1]/9;
691 2         4 push @clist, $x27[$x];
692 2         4 $x = ($tail[1] % 9) * 3;
693             }
694 4         8 push @clist, $x27[$x];
695             }
696              
697 6 50       43 return wantarray? @clist: join "", @clist;
698             }
699              
700             =head1 SEE ALSO
701              
702             =head2 The Base81 Character Set
703              
704             The Base81 character set is adapted from the Base85 character set
705             described by Robert Elz in his RFC1924 of April 1st 1996,
706             L<"A Compact Representation of IPv6 Addresses"|https://tools.ietf.org/html/rfc1924>
707             which are made up from the 94 printable ASCII characters, minus
708             quote marks, comma, slash and backslash, and the brackets.
709              
710             Despite it being an
711             L,
712             the reasoning for the choice of characters for the set was solid, and
713             Base81 uses them minus four more characters, the angle brackets, the
714             ampersand, and the accent mark.
715              
716             This reduces the character set to:
717              
718             '0'..'9', 'A'..'Z', 'a'..'z', '!', '#', '$', '%', '(',
719             ')', '*', '+', '-', ';', '=', '?', '@', '^', '_', '{',
720             '|', '}', and '~'.
721              
722             and allows the encoded data to be used without issue in JSON or XML.
723              
724             =cut
725              
726             =head2 Ascii85
727              
728             Base81 is a subset of Base85, which is similar in concept to
729             L, a format developed for
730             the btoa program, and later adopted with changes by Adobe for
731             Postscript's ASCII85Encode filter. There are, of course, modules on CPAN
732             that provide these formats.
733              
734             =over 3
735              
736             =item
737              
738             L
739              
740             =item
741              
742             L
743              
744             =item
745              
746             L
747              
748             =back
749              
750             =head2 Base64
751              
752             L encoding is an eight-bit to six-bit
753             encoding scheme that, depending on the characters used for encoding, has been used
754             for uuencode and MIME transfer, among many other formats. There are, of course,
755             modules on CPAN that provide these formats.
756              
757             =over 3
758              
759             =item
760              
761             L
762              
763             =item
764              
765             L
766              
767             =back
768              
769             =head1 AUTHOR
770              
771             John M. Gamble C<< >>
772              
773             =head1 BUGS
774              
775             Please report any bugs or feature requests to C,
776             or through the web interface at L.
777             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
778              
779             =head1 SUPPORT
780              
781             This module is on Github at L.
782              
783             You can also look for information on L.
784              
785             =head1 LICENSE AND COPYRIGHT
786              
787             Copyright (c) 2019 John M. Gamble.
788              
789             This program is free software; you can redistribute it and/or modify it
790             under the terms of either: the GNU General Public License as published
791             by the Free Software Foundation; or the Artistic License.
792              
793             See L for more information.
794              
795              
796             1;
797              
798             __END__