1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 let b64_pattern plus slash
=
21 [| 'A'
; 'B'
; 'C'
; 'D'
; 'E'
; 'F'
; 'G'
; 'H'
; 'I'
; 'J'
; 'K'
; 'L'
; 'M'
;
22 'N'
; 'O'
; 'P'
; 'Q'
; 'R'
; 'S'
; 'T'
; 'U'
; 'V'
; 'W'
; 'X'
; 'Y'
; 'Z'
;
23 'a'
; 'b'
; 'c'
; 'd'
; 'e'
; 'f'
; 'g'
; 'h'
; 'i'
; 'j'
; 'k'
; 'l'
; 'm'
;
24 'n'
; 'o'
; 'p'
; 'q'
; 'r'
; 's'
; 't'
; 'u'
; 'v'
; 'w'
; 'x'
; 'y'
; 'z'
;
25 '
0'
; '
1'
; '
2'
; '
3'
; '
4'
; '
5'
; '
6'
; '
7'
; '
8'
; '
9'
; plus
; slash
|];;
28 let rfc_pattern = b64_pattern '
+' '
/'
;;
29 let url_pattern = b64_pattern '
-' '
/'
;;
31 let encode_with_options b64 equal s pos len linelen crlf
=
32 (* encode using "base64".
33 * 'b64': The encoding table, created by b64_pattern.
34 * 'equal': The character that should be used instead of '=' in the original
35 * encoding scheme. Pass '=' to get the original encoding scheme.
36 * s, pos, len, linelen: See the interface description of encode_substring.
38 assert (Array.length b64
= 64);
39 if len
< 0 or pos
< 0 or pos
> String.length s
or linelen
< 0 then
40 invalid_arg
"Netencoding.Base64.encode_with_options";
41 if pos
+ len
> String.length s
then
42 invalid_arg
"Netencoding.Base64.encode_with_options";
47 let l_t = if len
= 0 then 0 else ((len
- 1) / 3 + 1) * 4 in
48 (* l_t: length of the result without additional line endings *)
54 if l_t = 0 then 0 else
55 let n_lines = ((l_t - 1) / linelen) + 1 in
56 l_t + n_lines * (if crlf
then 2 else 1)
58 (* l_t': length of the result with CRLF or LF characters *)
60 let t = String.make
l_t' equal
in
63 for k
= 0 to len
/ 3 - 1 do
65 (* p >= pos >= 0: this is evident
66 * p+2 < pos+len <= String.length s:
67 * Because k <= len/3-1
68 * 3*k <= 3*(len/3-1) = len - 3
69 * pos+3*k+2 <= pos + len - 3 + 2 = pos + len - 1 < pos + len
70 * So it is proved that the following unsafe string accesses always
73 let bits = (Char.code
(String.unsafe_get s
(p)) lsl 16) lor
74 (Char.code
(String.unsafe_get s
(p+1)) lsl 8) lor
75 (Char.code
(String.unsafe_get s
(p+2))) in
76 (* Obviously, 'bits' is a 24 bit entity (i.e. bits < 2**24) *)
77 assert(!j + 3 < l_t'
);
78 String.unsafe_set
t !j (Array.unsafe_get b64
( bits lsr 18));
79 String.unsafe_set
t (!j+1) (Array.unsafe_get b64
((bits lsr 12) land 63));
80 String.unsafe_set
t (!j+2) (Array.unsafe_get b64
((bits lsr 6) land 63));
81 String.unsafe_set
t (!j+3) (Array.unsafe_get b64
( bits land 63));
83 if linelen > 3 then begin
85 if !q + 4 > linelen then begin
86 (* The next 4 characters won't fit on the current line. So insert
102 (* padding if needed: *)
108 let bits = Char.code
(s
.[pos
+ len
- 1]) in
109 t.[ !j ] <- b64
.( bits lsr 2);
110 t.[ !j + 1 ] <- b64
.( (bits land 0x03) lsl 4);
114 let bits = (Char.code
(s
.[pos
+ len
- 2]) lsl 8) lor
115 (Char.code
(s
.[pos
+ len
- 1])) in
116 t.[ !j ] <- b64
.( bits lsr 10);
117 t.[ !j + 1 ] <- b64
.((bits lsr 4) land 0x3f);
118 t.[ !j + 2 ] <- b64
.((bits lsl 2) land 0x3f);
124 (* If required, add another line end: *)
126 if linelen > 3 && !q > 0 then begin
129 t.[ !j+1 ] <- '
\010'
;
143 encode_with_options rfc_pattern '
=' s
0 (String.length s
) 0 false;;
146 let encode_substring s pos len
=
147 encode_with_options rfc_pattern '
=' s pos len
0 false;;
150 let url_encode ?
(pos
=0) ?len ?
(linelength
=0) ?
(crlf
=false) s
=
151 let l = match len
with None
-> String.length s
- pos
| Some x
-> x
in
152 encode_with_options url_pattern '
.' s pos
l linelength crlf
;;
155 let decode_substring t ~pos ~len ~url_variant
:p_url ~accept_spaces
:p_spaces
=
156 if len
< 0 or pos
< 0 or pos
> String.length
t then
157 invalid_arg
"Netencoding.Base64.decode_substring";
158 if pos
+ len
> String.length
t then
159 invalid_arg
"Netencoding.Base64.decode_substring";
161 (* Compute the number of effective characters l_t in 't';
162 * pad_chars: number of '=' characters at the end of the string.
165 if p_spaces
then begin
166 (* Count all non-whitespace characters: *)
169 for i
= pos
to pos
+ len
- 1 do
170 match String.unsafe_get
t i
with
171 (' '
|'
\t'
|'
\r'
|'
\n'
) -> ()
173 if ch
= '
.'
&& not p_url
then
174 invalid_arg
"Netencoding.Base64.decode_substring";
178 invalid_arg
"Netencoding.Base64.decode_substring";
179 for j = i
+1 to pos
+ len
- 1 do
180 match String.unsafe_get
t j with
181 (' '
|'
\t'
|'
\r'
|'
\n'
|'
.'
|'
='
) -> ()
183 (* Only another '=' or spaces allowed *)
184 invalid_arg
"Netencoding.Base64.decode_substring";
188 if !c mod 4 <> 0 then
189 invalid_arg
"Netencoding.Base64.decode_substring";
194 ( if len
mod 4 <> 0 then
195 invalid_arg
"Netencoding.Base64.decode_substring";
197 if String.sub
t (len
- 2) 2 = "==" ||
198 (p_url
&& String.sub
t (len
- 2) 2 = "..") then 2
200 if String.sub
t (len
- 1) 1 = "=" ||
201 (p_url
&& String.sub
t (len
- 1) 1 = ".") then 1
209 let l_s = (l_t / 4) * 3 - pad_chars
in (* sic! *)
210 let s = String.create
l_s in
214 'A'
.. 'Z'
-> Char.code
(c) - 65 (* 65 = Char.code 'A' *)
215 | 'a'
.. 'z'
-> Char.code
(c) - 71 (* 71 = Char.code 'a' - 26 *)
216 | '
0'
.. '
9'
-> Char.code
(c) + 4 (* -4 = Char.code '0' - 52 *)
218 | '
-'
-> if not p_url
then
219 invalid_arg
"Netencoding.Base64.decode_substring";
222 | _
-> invalid_arg
"Netencoding.Base64.decode_substring";
225 (* Decode all but the last quartet: *)
227 let cursor = ref pos
in
228 let rec next_char() =
229 match t.[ !cursor ] with
230 (' '
|'
\t'
|'
\r'
|'
\n'
) ->
231 if p_spaces
then (incr
cursor; next_char())
232 else invalid_arg
"Netencoding.Base64.decode_substring"
237 if p_spaces
then begin
238 for k
= 0 to l_t / 4 - 2 do
240 let c0 = next_char() in
241 let c1 = next_char() in
242 let c2 = next_char() in
243 let c3 = next_char() in
244 let n0 = decode_char c0 in
245 let n1 = decode_char c1 in
246 let n2 = decode_char c2 in
247 let n3 = decode_char c3 in
248 let x0 = (n0 lsl 2) lor (n1 lsr 4) in
249 let x1 = ((n1 lsl 4) land 0xf0) lor (n2 lsr 2) in
250 let x2 = ((n2 lsl 6) land 0xc0) lor n3 in
251 String.unsafe_set
s q (Char.chr
x0);
252 String.unsafe_set
s (q+1) (Char.chr
x1);
253 String.unsafe_set
s (q+2) (Char.chr
x2);
258 for k
= 0 to l_t / 4 - 2 do
261 let c0 = String.unsafe_get
t p in
262 let c1 = String.unsafe_get
t (p + 1) in
263 let c2 = String.unsafe_get
t (p + 2) in
264 let c3 = String.unsafe_get
t (p + 3) in
265 let n0 = decode_char c0 in
266 let n1 = decode_char c1 in
267 let n2 = decode_char c2 in
268 let n3 = decode_char c3 in
269 let x0 = (n0 lsl 2) lor (n1 lsr 4) in
270 let x1 = ((n1 lsl 4) land 0xf0) lor (n2 lsr 2) in
271 let x2 = ((n2 lsl 6) land 0xc0) lor n3 in
272 String.unsafe_set
s q (Char.chr
x0);
273 String.unsafe_set
s (q+1) (Char.chr
x1);
274 String.unsafe_set
s (q+2) (Char.chr
x2);
276 cursor := pos
+ l_t - 4;
279 (* Decode the last quartet: *)
281 if l_t > 0 then begin
282 let q = 3*(l_t / 4 - 1) in
283 let c0 = next_char() in
284 let c1 = next_char() in
285 let c2 = next_char() in
286 let c3 = next_char() in
288 if (c2 = '
='
&& c3 = '
='
) or (p_url
&& c2 = '
.'
&& c3 = '
.'
) then begin
289 let n0 = decode_char c0 in
290 let n1 = decode_char c1 in
291 let x0 = (n0 lsl 2) lor (n1 lsr 4) in
292 s.[ q ] <- Char.chr
x0;
295 if (c3 = '
='
) or (p_url
&& c3 = '
.'
) then begin
296 let n0 = decode_char c0 in
297 let n1 = decode_char c1 in
298 let n2 = decode_char c2 in
299 let x0 = (n0 lsl 2) lor (n1 lsr 4) in
300 let x1 = ((n1 lsl 4) land 0xf0) lor (n2 lsr 2) in
301 s.[ q ] <- Char.chr
x0;
302 s.[ q+1 ] <- Char.chr
x1;
305 let n0 = decode_char c0 in
306 let n1 = decode_char c1 in
307 let n2 = decode_char c2 in
308 let n3 = decode_char c3 in
309 let x0 = (n0 lsl 2) lor (n1 lsr 4) in
310 let x1 = ((n1 lsl 4) land 0xf0) lor (n2 lsr 2) in
311 let x2 = ((n2 lsl 6) land 0xc0) lor n3 in
312 s.[ q ] <- Char.chr
x0;
313 s.[ q+1 ] <- Char.chr
x1;
314 s.[ q+2 ] <- Char.chr
x2;
324 decode_substring s 0 (String.length
s) false false