Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | #!/usr/bin/perl |
2 | # base64.pl -- A perl package to handle MIME-style BASE64 encoding | |
3 | # A. P. Barrett <barrett@ee.und.ac.za>, October 1993 | |
4 | # $Revision: 2.2 $$Date: 2001/09/05 11:53:01 $ | |
5 | # | |
6 | # $Id: base64.pl,v 2.2 2001/09/05 11:53:01 ehood Exp $ | |
7 | # | |
8 | # Modified March 21, 1996 by ehood@convex.com | |
9 | # -> Changes to base64'uudecode to strip out any begin/end | |
10 | # lines from input string. | |
11 | # | |
12 | # Modified April 16, 1996 by ehood@convex.com | |
13 | # -> Change in base64'b64decode to use substr() to extract | |
14 | # data for decoding instead of a regular expression. | |
15 | # Results in a huge increase in execution time under Perl 4. | |
16 | # Perl 5 regular expression capability could be used to | |
17 | # give comperable performance, but would break Perl 4 | |
18 | # compatibility. Also, the substr() algorithm appears | |
19 | # to edge out the perl 5 method. | |
20 | # | |
21 | # Other functions have not been changed to use substr(), but | |
22 | # may benefit from it. | |
23 | # | |
24 | # Modified February 20, 1998 by ehood@medusa.acs.uci.edu | |
25 | # -> Removed all uses of $&. | |
26 | ||
27 | package base64; | |
28 | ||
29 | # Synopsis: | |
30 | # require 'base64.pl'; | |
31 | # | |
32 | # $uuencode_string = &base64::b64touu($base64_string); | |
33 | # $binary_string = &base64::b64decode($base64_string); | |
34 | # $base64_string = &base64::uutob64($uuencode_string); | |
35 | # $base64_string = &base64::b64encode($binary_string); | |
36 | # $uuencode_string = &base64::uuencode($binary_string); | |
37 | # $binary_string = &base64::uudecode($uuencode_string); | |
38 | # | |
39 | # uuencode and base64 input strings may contain multiple lines, | |
40 | # but may not contain any headers or trailers. (For uuencode, | |
41 | # remove the begin and end lines, and for base64, remove the MIME | |
42 | # headers and boundaries.) | |
43 | # | |
44 | # uuencode and base64 output strings will be contain multiple | |
45 | # lines if appropriate, but will not contain any headers or | |
46 | # trailers. (For uuencode, add the "begin" line and the | |
47 | # " \nend\n" afterwards, and for base64, add any MIME stuff | |
48 | # afterwards.) | |
49 | ||
50 | #################### | |
51 | ||
52 | $base64_alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. | |
53 | 'abcdefghijklmnopqrstuvwxyz'. | |
54 | '0123456789+/'; | |
55 | $base64_pad = '='; | |
56 | ||
57 | $uuencode_alphabet = q|`!"#$%&'()*+,-./0123456789:;<=>?|. | |
58 | '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; # double that '\\'! | |
59 | $uuencode_pad = '`'; | |
60 | ||
61 | # Build some strings for use in tr/// commands. | |
62 | # Some uuencodes use " " and some use "`", so we handle both. | |
63 | # We also need to protect backslashes and other special characters. | |
64 | $tr_uuencode = " ".$uuencode_alphabet; | |
65 | $tr_uuencode =~ s/(\W)/\\$1/g; | |
66 | $tr_base64 = "A".$base64_alphabet; | |
67 | $tr_base64 =~ s/(\W)/\\$1/g; | |
68 | ||
69 | sub b64touu | |
70 | { | |
71 | local ($_) = shift; | |
72 | my ($result); | |
73 | ||
74 | # zap bad characters and translate others to uuencode alphabet | |
75 | eval qq{ | |
76 | tr|$tr_base64||cd; | |
77 | tr|$tr_base64|$tr_uuencode|; | |
78 | }; | |
79 | ||
80 | # break into lines of 60 encoded chars, prepending "M" for uuencode | |
81 | while (s/^(.{60})//) { | |
82 | $result .= "M" . $1 . "\n"; | |
83 | } | |
84 | ||
85 | # any leftover chars go onto a shorter line | |
86 | # with padding to the next multiple of 4 chars | |
87 | if ($_ ne "") { | |
88 | $result .= substr($uuencode_alphabet, length($_)*3/4, 1) | |
89 | . $_ | |
90 | . ($uuencode_pad x ((60 - length($_)) % 4)) . "\n"; | |
91 | } | |
92 | ||
93 | # return result | |
94 | $result; | |
95 | } | |
96 | ||
97 | sub b64decode | |
98 | { | |
99 | # substr() usage added by ehood, 1996/04/16 | |
100 | ||
101 | local($str) = shift; | |
102 | local($result, $tmp, $offset, $len); | |
103 | ||
104 | # zap bad characters and translate others to uuencode alphabet | |
105 | eval qq{ | |
106 | \$str =~ tr|$tr_base64||cd; | |
107 | \$str =~ tr|$tr_base64|$tr_uuencode|; | |
108 | }; | |
109 | ||
110 | # break into lines of 60 encoded chars, prepending "M" for uuencode, | |
111 | # and then using perl's builtin uudecoder to convert to binary. | |
112 | # | |
113 | $result = ''; # init return string | |
114 | $offset = 0; # init offset to 0 | |
115 | $len = length($str); # store length | |
116 | while ($offset+60 <= $len) { # loop until < 60 chars left | |
117 | $tmp = substr($str, $offset, 60); # grap 60 char block | |
118 | $offset += 60; # increment offset | |
119 | $result .= unpack("u", "M" . $tmp); # decode block | |
120 | } | |
121 | # also decode any leftover chars | |
122 | if ($offset < $len) { | |
123 | $tmp = substr($str, $offset, $len-$offset); | |
124 | $result .= unpack("u", | |
125 | substr($uuencode_alphabet, length($tmp)*3/4, 1) . $tmp); | |
126 | } | |
127 | ||
128 | # return result | |
129 | $result; | |
130 | } | |
131 | ||
132 | sub uutob64 | |
133 | { | |
134 | local ($_) = @_; | |
135 | local ($result); | |
136 | ||
137 | # This is the most difficult, because some perverse uuencoder | |
138 | # might have made lines that do not describe multiples of 3 bytes. | |
139 | # I don't see any better method than uudecoding to binary and then | |
140 | # b64encoding the binary. | |
141 | ||
142 | &b64encode(&uudecode); # implicitly pass @_ to &uudecode | |
143 | } | |
144 | ||
145 | sub b64encode | |
146 | { | |
147 | local ($_) = @_; | |
148 | my ($chunk); | |
149 | my ($result); | |
150 | ||
151 | # break into chunks of 45 input chars, use perl's builtin | |
152 | # uuencoder to convert each chunk to uuencode format, | |
153 | # then kill the leading "M", translate to the base64 alphabet, | |
154 | # and finally append a newline. | |
155 | while (s/^([\s\S]{45})//) { | |
156 | #warn "in:$1:\n"; | |
157 | $chunk = substr(pack("u", $1), $[+1, 60); | |
158 | #warn "packed :$chunk:\n"; | |
159 | eval qq{ | |
160 | \$chunk =~ tr|$tr_uuencode|$tr_base64|; | |
161 | }; | |
162 | #warn "translated:$chunk:\n"; | |
163 | $result .= $chunk . "\n"; | |
164 | } | |
165 | ||
166 | # any leftover chars go onto a shorter line | |
167 | # with uuencode padding converted to base64 padding | |
168 | if ($_ ne "") { | |
169 | #warn "length ".length($_)." \$_:$_:\n"; | |
170 | #warn "enclen ", int((length($_)+2)/3)*4 - (45-length($_))%3, "\n"; | |
171 | $chunk = substr(pack("u", $_), $[+1, | |
172 | int((length($_)+2)/3)*4 - (45-length($_))%3); | |
173 | #warn "chunk:$chunk:\n"; | |
174 | eval qq{ | |
175 | \$chunk =~ tr|$tr_uuencode|$tr_base64|; | |
176 | }; | |
177 | #warn "translated:$chunk:\n"; | |
178 | $result .= $chunk . ($base64_pad x ((60 - length($chunk)) % 4)) . "\n"; | |
179 | } | |
180 | ||
181 | # return result | |
182 | $result; | |
183 | } | |
184 | ||
185 | sub uuencode | |
186 | { | |
187 | local ($_) = @_; | |
188 | local ($result); | |
189 | ||
190 | # break into chunks of 45 input chars, and use perl's builtin | |
191 | # uuencoder to convert each chunk to uuencode format. | |
192 | # (newline is added by builtin uuencoder.) | |
193 | while (s/^([\s\S]{45})//) { | |
194 | $result .= pack("u", $1); | |
195 | } | |
196 | ||
197 | # any leftover chars go onto a shorter line | |
198 | # with padding to the next multiple of 4 chars | |
199 | if ($_ ne "") { | |
200 | $result .= pack("u", $_); | |
201 | } | |
202 | ||
203 | # return result | |
204 | $result; | |
205 | } | |
206 | ||
207 | sub uudecode | |
208 | { | |
209 | local ($_) = shift; | |
210 | my $result = ''; | |
211 | ||
212 | # strip out begin/end lines (ehood, 1996/03/21) | |
213 | s/^\s*begin[^\n]+\n//; | |
214 | s/\nend\s*$//; | |
215 | ||
216 | # use perl's builtin uudecoder to convert each line | |
217 | while (s/^([^\n]+\n?)//) { | |
218 | last if substr($1, 0, 1) eq '`'; | |
219 | $result .= unpack('u', $1); | |
220 | } | |
221 | ||
222 | # return result | |
223 | $result; | |
224 | } |