kythe.io@v0.0.68-0.20240422202219-7225dbc01741/third_party/ocaml_b64/b64.ml (about) 1 (* 2 * Copyright (c) 2006-2009 Citrix Systems Inc. 3 * Copyright (c) 2010 Thomas Gazagnaire <thomas@gazagnaire.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 *) 18 19 module Bytes = String 20 21 let default_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" 22 let uri_safe_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" 23 let padding = '=' 24 25 let of_char ?(alphabet=default_alphabet) x = 26 if x = padding then 0 else String.index alphabet x 27 28 let to_char ?(alphabet=default_alphabet) x = 29 alphabet.[x] 30 31 let decode ?alphabet input = 32 let length = String.length input in 33 let input = 34 if length mod 4 = 0 then input 35 else input ^ (String.make (4 - length mod 4) padding) 36 in 37 let length = String.length input in 38 let words = length / 4 in 39 let padding = 40 match length with 41 | 0 -> 0 42 | _ when input.[length - 2] = padding -> 2 43 | _ when input.[length - 1] = padding -> 1 44 | _ -> 0 45 in 46 let output = Bytes.make (words * 3 - padding) '\000' in 47 for i = 0 to words - 1 do 48 let a = of_char ?alphabet (String.get input (4 * i + 0)) 49 and b = of_char ?alphabet (String.get input (4 * i + 1)) 50 and c = of_char ?alphabet (String.get input (4 * i + 2)) 51 and d = of_char ?alphabet (String.get input (4 * i + 3)) in 52 let n = (a lsl 18) lor (b lsl 12) lor (c lsl 6) lor d in 53 let x = (n lsr 16) land 255 54 and y = (n lsr 8) land 255 55 and z = n land 255 in 56 Bytes.set output (3 * i + 0) (char_of_int x); 57 if i <> words - 1 || padding < 2 then 58 Bytes.set output (3 * i + 1) (char_of_int y); 59 if i <> words - 1 || padding < 1 then 60 Bytes.set output (3 * i + 2) (char_of_int z); 61 done; 62 (*Bytes.unsafe_to_string*) output 63 64 let encode ?(pad=true) ?alphabet input = 65 let length = String.length input in 66 let words = (length + 2) / 3 in (* rounded up *) 67 let padding_len = if length mod 3 = 0 then 0 else 3 - (length mod 3) in 68 let output = Bytes.make (words * 4) '\000' in 69 let get i = if i >= length then 0 else int_of_char input.[i] in 70 for i = 0 to words - 1 do 71 let x = get (3 * i + 0) 72 and y = get (3 * i + 1) 73 and z = get (3 * i + 2) in 74 let n = (x lsl 16) lor (y lsl 8) lor z in 75 let a = (n lsr 18) land 63 76 and b = (n lsr 12) land 63 77 and c = (n lsr 6) land 63 78 and d = n land 63 in 79 Bytes.set output (4 * i + 0) (to_char ?alphabet a); 80 Bytes.set output (4 * i + 1) (to_char ?alphabet b); 81 Bytes.set output (4 * i + 2) (to_char ?alphabet c); 82 Bytes.set output (4 * i + 3) (to_char ?alphabet d); 83 done; 84 for i = 1 to padding_len do 85 Bytes.set output (Bytes.length output - i) padding; 86 done; 87 if pad then (*Bytes.unsafe_to_string*) output 88 else (*Bytes.sub_string*) String.sub output 0 (Bytes.length output - padding_len)