1 2=head1 NAME 3 4MIME::Base64 - Encoding and decoding of base64 strings 5 6=head1 SYNOPSIS 7 8 # load this library 9 load_bytecode 'MIME/Base64.pbc' 10 11=head1 DESCRIPTION 12 13MIME::Base64 is inspired by the Perl5 module MIME::Base64. 14 15=head1 METHODS 16 17This module defines the following subroutines: 18 19=over 4 20 21=item C<encode_base64( str )> 22 23Encode data by calling the encode_base64() function. The first argument 24is the string to encode. 25The returned encoded string is broken into lines 26of no more than 76 characters each. 27 28Note: Unicode stored as MIME::Base64 is inherently endian-dependent. 29 30=item C<decode_base64( str, ?:encoding )> 31 32Decode a base64 string by calling the decode_base64() function. 33This function takes as first argument the string to decode, 34as optional second argument the encoding string for the decoded data. 35It returns the decoded data. 36 37Any character not part of the 65-character base64 subset is silently ignored. 38Characters occurring after a '=' padding character are never decoded. 39 40=back 41 42=cut 43 44.include "iterator.pasm" 45 46.namespace [ "MIME"; "Base64" ] 47 48.sub init :load 49 50 # Base64 encoded strings are made of printable 8bit long chars, 51 # of which each carries 6 bit worth of information 52 .local string printables 53 printables = ascii:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" 54 55 # TODO: find saner names 56 .local pmc six_to_eight, eight_to_six 57 six_to_eight = new 'FixedIntegerArray' 58 six_to_eight = 64 # 2 ** 6 59 eight_to_six = new 'FixedIntegerArray' 60 eight_to_six = 256 # 2 ** 8 61 62 # TODO: find easier way to initialize with undef or so 63 eight_to_six[0] = 0 64 .local int i 65 i = 1 66 START_2: 67 if i >= 256 goto END_2 68 eight_to_six[i] = -1 69 inc i 70 goto START_2 71 END_2: 72 73 .local int six, eight 74 .local string tmp 75 six = 0 76 START_1: 77 tmp = substr printables, six, 1 78 eight = ord tmp 79 eight_to_six[eight] = six 80 six_to_eight[six] = eight 81 inc six 82 if six < 64 goto START_1 83 set_global 'eight_to_six', eight_to_six 84 set_global 'six_to_eight', six_to_eight 85.end 86 87.sub encode_base64 88 .param string plain 89 90 .local string base64 91 .local pmc six_to_eight 92 six_to_eight = get_global 'six_to_eight' 93 94 .local int len, len_mod_3 95 .local pmc bb 96 # For unicode we cannot use chr/ord. This breaks endianness. 97 # GH 813 and #814 98 len = bytelength plain 99 bb = new ['ByteBuffer'], len 100 bb = plain 101 102 len_mod_3 = len % 3 103 # Fill up with with null bytes 104 if len_mod_3 == 0 goto END_1 105 push bb, 0 106 if len_mod_3 == 2 goto END_1 107 push bb, 0 108 END_1: 109 110 base64 = '' 111 112 .local int i, j 113 .local int eight_0, eight_1, eight_2 114 .local int six_0, six_1, six_2, six_3 115 .local int tmp_int_1, tmp_int_2 116 .local string s_tmp_1 117 118 i = 0 119 j = 0 120 START_3: 121 if i >= len goto END_3 122 123 # read 3*8 bits 124 eight_0 = bb[i] 125 inc i 126 eight_1 = bb[i] 127 inc i 128 eight_2 = bb[i] 129 inc i 130 131 # d[i]>>2; 132 shr six_0, eight_0, 2 133 134 # ((d[i]&3)<<4) | (d[i+1]>>4) 135 band tmp_int_1, eight_0, 3 136 shl tmp_int_1, 4 137 shr tmp_int_2, eight_1, 4 138 bor six_1, tmp_int_1, tmp_int_2 139 140 # ((d[i+1]&15)<<2) | (d[i+2]>>6) 141 band tmp_int_1, eight_1, 15 142 shl tmp_int_1, 2 143 shr tmp_int_2, eight_2, 6 144 bor six_2, tmp_int_1, tmp_int_2 145 146 # d[i+2]&63 147 band six_3, eight_2, 63 148 149 # write 4*6 bits, encoded as 4*8 bits, 150 # output is larger than input 151 tmp_int_1 = six_to_eight[six_0] 152 s_tmp_1 = chr tmp_int_1 153 base64 = concat base64, s_tmp_1 154 tmp_int_1 = six_to_eight[six_1] 155 s_tmp_1 = chr tmp_int_1 156 base64 = concat base64, s_tmp_1 157 tmp_int_1 = six_to_eight[six_2] 158 s_tmp_1 = chr tmp_int_1 159 base64 = concat base64, s_tmp_1 160 tmp_int_1 = six_to_eight[six_3] 161 s_tmp_1 = chr tmp_int_1 162 base64 = concat base64, s_tmp_1 163 inc j 164 165 if j == 19 goto line_split 166 goto START_3 167 line_split: 168 base64 = concat base64, "\n" 169 j = 0 170 goto START_3 171 END_3: 172 173 # padding with '=' 174 if len_mod_3 == 0 goto END_2 175 base64 = replace base64, -1, 1, ascii:"=" 176 if len_mod_3 == 2 goto END_2 177 base64 = replace base64, -2, 1, ascii:"=" 178 END_2: 179 180 .return( base64 ) 181.end 182 183.sub decode_base64 184 .param string base64 185 .param string enc :optional 186 .param int has_enc :opt_flag 187 188 .local string result, base64_cleaned 189 .local int enc_num 190 base64_cleaned = '' 191 if has_enc goto HAS_ENC 192 enc = 'ascii' 193 HAS_ENC: 194 195 .local pmc eight_to_six, bb 196 eight_to_six = get_global 'eight_to_six' 197 198 .local int i, len 199 .local int tmp_int_1, tmp_int_2 200 201 # Get rid of non-base64 chars 202 len = length base64 203 i = 0 204 START_5: 205 .local string s_tmp_1 206 if i >= len goto END_5 207 tmp_int_1 = ord base64, i 208 inc i 209 tmp_int_2 = eight_to_six[tmp_int_1] 210 if tmp_int_2 == -1 goto START_5 211 s_tmp_1 = chr tmp_int_1 212 base64_cleaned = concat base64_cleaned, s_tmp_1 213 goto START_5 214 215 END_5: 216 .local int len_mod_4 217 len = length base64_cleaned 218 len_mod_4 = len % 4 219 220 # make sure that there are dummy bits beyond 221 base64_cleaned = concat base64_cleaned, ascii:"\0\0\0" 222 223 bb = new ['ByteBuffer'] 224 .local int eight_0, eight_1, eight_2 225 .local int six_0, six_1, six_2, six_3 226 227 i = 0 228 START_2: 229 if i >= len goto END_2 230 231 # read 4*6 bits 232 tmp_int_1 = ord base64_cleaned, i 233 six_0 = eight_to_six[tmp_int_1] 234 inc i 235 tmp_int_1 = ord base64_cleaned, i 236 six_1 = eight_to_six[tmp_int_1] 237 inc i 238 tmp_int_1 = ord base64_cleaned, i 239 six_2 = eight_to_six[tmp_int_1] 240 inc i 241 tmp_int_1 = ord base64_cleaned, i 242 six_3 = eight_to_six[tmp_int_1] 243 inc i 244 245 # (f64[t.charAt(i)]<<2) | (f64[t.charAt(i+1)]>>4) 246 shl tmp_int_1, six_0, 2 247 shr tmp_int_2, six_1, 4 248 bor eight_0, tmp_int_1, tmp_int_2 249 250 # (f64[t.charAt(i+1)]&15)<<4) | (f64[t.charAt(i+2)]>>2) 251 band tmp_int_1, six_1, 15 252 shl tmp_int_1, 4 253 shr tmp_int_2, six_2, 2 254 bor eight_1, tmp_int_1, tmp_int_2 255 256 # (f64[t.charAt(i+2)]&3)<<6) | (f64[t.charAt(i+3)]) 257 band tmp_int_1, six_2, 3 258 shl tmp_int_1, 6 259 bor eight_2, tmp_int_1, six_3 260 261 # write 3*8 bits 262 # output is larger than input 263 push bb, eight_0 264 push bb, eight_1 265 push bb, eight_2 266 goto START_2 267 268 END_2: 269 # cut padded '=' 270 if len_mod_4 == 0 goto END_3 271 if len_mod_4 == 1 goto END_3 272 len = elements bb 273 dec len 274 bb = len 275 if len_mod_4 == 3 goto END_3 276 dec len 277 bb = len 278 279 END_3: 280 result = bb.'get_string'(enc) 281 .return( result ) 282.end 283 284=head1 SEE ALSO 285 286L<http://aktuell.de.selfhtml.org/artikel/javascript/utf8b64/base64.htm> 287L<http://en.wikipedia.org/wiki/Base64> 288 289=head1 AUTHOR 290 291Written and maintained by Bernhard Schmalhofer, 292C<< Bernhard dot Schmalhofer at gmx dot de >>, 293based on the Perl 5 Module MIME::Base64 by Gisle Aas 294and on the article on de.selfhtml.org. 295 296=head1 COPYRIGHT 297 298Copyright (C) 2006-2012, Parrot Foundation. 299 300=cut 301 302# Local Variables: 303# mode: pir 304# fill-column: 100 305# End: 306# vim: expandtab shiftwidth=4 ft=pir: 307