-- Copyright (c) Ian Lynagh, 2005, 2007.moduleCodec.Binary.Base64.String(encode,decode)whereimportData.Bits(shiftL,shiftR,(.&.),(.|.))importData.Char(ord,chr,isAscii,isAlphaNum,isUpper,isLower,isDigit)importData.List(intersperse)chars_per_line::Intchars_per_line=64-- PEM mandates 64. MIME allows anything up to 76.encode::String->Stringencode=concat.intersperse"\n".splitschars_per_line.enc-- It is up to the caller to make sure the right sort of line breaks are-- in the inputenc::String->Stringenc(c1:c2:c3:cs)=toChar(o1`shiftR`2)-- First 6 bits of c1:toChar(((o1`shiftL`4).&.0x30)-- Last 2 bits of c1.|.(o2`shiftR`4))-- First 4 bits of c2:toChar(((o2`shiftL`2).&.0x3C)-- Last 4 bits of c2.|.(o3`shiftR`6))-- First 2 bits of c3:toChar(o3.&.0x3F)-- Last 6 bits of c3:enccswhereo1=ordc1o2=ordc2o3=ordc3enc[c1,c2]=toChar(o1`shiftR`2)-- First 6 bits of c1:toChar(((o1`shiftL`4).&.0x30)-- Last 2 bits of c1.|.(o2`shiftR`4))-- First 4 bits of c2:toChar((o2`shiftL`2).&.0x3C)-- Last 4 bits of c2:"="whereo1=ordc1o2=ordc2enc[c1]=toChar(o1`shiftR`2)-- First 6 bits of c1:toChar((o1`shiftL`4).&.0x30)-- Last 2 bits of c1:"=="whereo1=ordc1enc""=""toChar::Int->ChartoCharn|n<=25=chr(ord'A'+n)|n<=51=chr(ord'a'+n-26)|n<=61=chr(ord'0'+n-52)|n==62='+'|n==63='/'|otherwise=error("toChar: Can't happen: Bad input: "++shown)decode::String->Stringdecode=dec.filtervalidwherevalidc=isAsciic&&(isAlphaNumc||c=='+'||c=='/'||c=='=')dec::String->Stringdec""=""dec('=':_)=""-- This can't be valid, so give updec(_:'=':_)=""-- This can't be valid, so give updec(c1:c2:'=':_)-- Should have [c1,c2,'=','='], but if not we'd decode-- this bit and stop anyway=take1$dec[c1,c2,'A','A']dec(c1:c2:c3:'=':_)-- Should have [c1,c2,c3,'='], but if not we'd decode-- this bit and stop anyway=take2$dec[c1,c2,c3,'A']dec(c1:c2:c3:c4:cs)=letx1=fromCharc1x2=fromCharc2x3=fromCharc3x4=fromCharc4in-- 6 bits from x1, 2 bits from x2chr((x1`shiftL`2).|.(x2`shiftR`4))-- 4 bits from x2, 4 bits from x3:chr(((x2`shiftL`4).&.0xF0).|.(x3`shiftR`2))-- 2 bits from x3, 6 bits from x4:chr(((x3`shiftL`6).&.0xC0).|.x4):deccs-- Drop more invalid thingsdec[_]=""dec[_,_]=""dec[_,_,_]=""fromChar::Char->IntfromCharc|isUpperc=ordc-ord'A'|isLowerc=ordc-ord'a'+26|isDigitc=ordc-ord'0'+52|c=='+'=62|c=='/'=63|otherwise=error("fromChar: Can't happen: Bad input: "++showc)splits::Int->[a]->[[a]]splits_[]=[]splitsnxs=casesplitAtnxsof(ys,zs)->ys:splitsnzs