1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192(*
* Copyright (c) 2006-2009 Citrix Systems Inc.
* Copyright (c) 2010 Thomas Gazagnaire <thomas@gazagnaire.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)letdefault_alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"leturi_safe_alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"letpadding='='letof_char?(alphabet=default_alphabet)x=ifx=paddingthen0elseString.indexalphabetxletto_char?(alphabet=default_alphabet)x=alphabet.[x]letdecode?alphabetinput=letlength=String.lengthinputinletinput=iflengthmod4=0theninputelseinput^String.make(4-(lengthmod4))paddinginletlength=String.lengthinputinletwords=length/4inletpadding=matchlengthwith|0->0|_wheninput.[length-2]=padding->2|_wheninput.[length-1]=padding->1|_->0inletoutput=Bytes.make((words*3)-padding)'\000'infori=0towords-1doleta=of_char?alphabetinput.[(4*i)+0]andb=of_char?alphabetinput.[(4*i)+1]andc=of_char?alphabetinput.[(4*i)+2]andd=of_char?alphabetinput.[(4*i)+3]inletn=(alsl18)lor(blsl12)lor(clsl6)lordinletx=(nlsr16)land255andy=(nlsr8)land255andz=nland255inBytes.setoutput((3*i)+0)(char_of_intx);ifi<>words-1||padding<2thenBytes.setoutput((3*i)+1)(char_of_inty);ifi<>words-1||padding<1thenBytes.setoutput((3*i)+2)(char_of_intz)done;Bytes.unsafe_to_stringoutputletdecode_opt?alphabetinput=trySome(decode?alphabetinput)withNot_found->Noneletencode?(pad=true)?alphabetinput=letlength=String.lengthinputinletwords=(length+2)/3(* rounded up *)inletpadding_len=iflengthmod3=0then0else3-(lengthmod3)inletoutput=Bytes.make(words*4)'\000'inletgeti=ifi>=lengththen0elseint_of_charinput.[i]infori=0towords-1doletx=get((3*i)+0)andy=get((3*i)+1)andz=get((3*i)+2)inletn=(xlsl16)lor(ylsl8)lorzinleta=(nlsr18)land63andb=(nlsr12)land63andc=(nlsr6)land63andd=nland63inBytes.setoutput((4*i)+0)(to_char?alphabeta);Bytes.setoutput((4*i)+1)(to_char?alphabetb);Bytes.setoutput((4*i)+2)(to_char?alphabetc);Bytes.setoutput((4*i)+3)(to_char?alphabetd)done;fori=1topadding_lendoBytes.setoutput(Bytes.lengthoutput-i)paddingdone;ifpadthenBytes.unsafe_to_stringoutputelseBytes.sub_stringoutput0(Bytes.lengthoutput-padding_len)