base64.ml 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. (*
  2. * Base64 - Base64 codec
  3. * Copyright (C) 2003 Nicolas Cannasse
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version,
  9. * with the special exception on linking described in file LICENSE.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *)
  20. open ExtBytes
  21. exception Invalid_char
  22. exception Invalid_table
  23. external unsafe_char_of_int : int -> char = "%identity"
  24. type encoding_table = char array
  25. type decoding_table = int array
  26. let chars = [|
  27. 'A';'B';'C';'D';'E';'F';'G';'H';'I';'J';'K';'L';'M';'N';'O';'P';
  28. 'Q';'R';'S';'T';'U';'V';'W';'X';'Y';'Z';'a';'b';'c';'d';'e';'f';
  29. 'g';'h';'i';'j';'k';'l';'m';'n';'o';'p';'q';'r';'s';'t';'u';'v';
  30. 'w';'x';'y';'z';'0';'1';'2';'3';'4';'5';'6';'7';'8';'9';'+';'/'
  31. |]
  32. let make_decoding_table tbl =
  33. if Array.length tbl <> 64 then raise Invalid_table;
  34. let d = Array.make 256 (-1) in
  35. for i = 0 to 63 do
  36. Array.unsafe_set d (int_of_char (Array.unsafe_get tbl i)) i;
  37. done;
  38. d
  39. let inv_chars = make_decoding_table chars
  40. let encode ?(tbl=chars) ch =
  41. if Array.length tbl <> 64 then raise Invalid_table;
  42. let data = ref 0 in
  43. let count = ref 0 in
  44. let flush() =
  45. if !count > 0 then begin
  46. let d = (!data lsl (6 - !count)) land 63 in
  47. IO.write ch (Array.unsafe_get tbl d);
  48. end;
  49. in
  50. let write c =
  51. let c = int_of_char c in
  52. data := (!data lsl 8) lor c;
  53. count := !count + 8;
  54. while !count >= 6 do
  55. count := !count - 6;
  56. let d = (!data asr !count) land 63 in
  57. IO.write ch (Array.unsafe_get tbl d)
  58. done;
  59. in
  60. let output s p l =
  61. for i = p to p + l - 1 do
  62. write (Bytes.unsafe_get s i)
  63. done;
  64. l
  65. in
  66. IO.create_out ~write ~output
  67. ~flush:(fun () -> flush(); IO.flush ch)
  68. ~close:(fun() -> flush(); IO.close_out ch)
  69. let decode ?(tbl=inv_chars) ch =
  70. if Array.length tbl <> 256 then raise Invalid_table;
  71. let data = ref 0 in
  72. let count = ref 0 in
  73. let rec fetch() =
  74. if !count >= 8 then begin
  75. count := !count - 8;
  76. let d = (!data asr !count) land 0xFF in
  77. unsafe_char_of_int d
  78. end else
  79. let c = int_of_char (IO.read ch) in
  80. let c = Array.unsafe_get tbl c in
  81. if c = -1 then raise Invalid_char;
  82. data := (!data lsl 6) lor c;
  83. count := !count + 6;
  84. fetch()
  85. in
  86. let read = fetch in
  87. let input s p l =
  88. let i = ref 0 in
  89. try
  90. while !i < l do
  91. Bytes.unsafe_set s (p + !i) (fetch());
  92. incr i;
  93. done;
  94. l
  95. with
  96. IO.No_more_input when !i > 0 ->
  97. !i
  98. in
  99. let close() =
  100. count := 0;
  101. IO.close_in ch
  102. in
  103. IO.create_in ~read ~input ~close
  104. let str_encode ?(tbl=chars) s =
  105. let ch = encode ~tbl (IO.output_bytes()) in
  106. IO.nwrite_string ch s;
  107. IO.close_out ch
  108. let str_decode ?(tbl=inv_chars) s =
  109. let ch = decode ~tbl (IO.input_bytes s) in
  110. IO.nread_string ch ((Bytes.length s * 6) / 8)
  111. let encode_string ?(tbl=chars) s =
  112. let ch = encode ~tbl (IO.output_string ()) in
  113. IO.nwrite_string ch s;
  114. IO.close_out ch
  115. let decode_string ?(tbl=inv_chars) s =
  116. let ch = decode ~tbl (IO.input_string s) in
  117. IO.nread_string ch ((String.length s * 6) / 8)