get_message() passes two tests
[libmime.git] / base64.myr
blob959c0396064016909be8b93081239cebe15b916e
1 /* part of RFC 2045 */
3 use std
5 use "util"
7 pkg mime =
8         const utf8_from_base64 : (encoded : byte[:] -> std.result(byte[:], void))
9 ;;
11 const b64_value = { b : byte
12         if ('A' : byte) <= b && b <= ('Z' : byte)
13                 -> `std.Some (b - ('A' : byte))
14         elif ('a' : byte) <= b && b <= ('z' : byte)
15                 -> `std.Some (b - ('a' : byte) + 26)
16         elif ('0' : byte) <= b && b <= ('9' : byte)
17                 -> `std.Some (b - ('0' : byte) + 52)
18         elif b == ('+' : byte)
19                 -> `std.Some 62
20         elif b == ('/' : byte)
21                 -> `std.Some 63
22         elif b == ('=' : byte)
23                 -> `std.Some 0
24         ;;
26         -> `std.None
27 }      
29 const utf8_from_base64 = { encoded : byte[:]
30         var decoded : std.strbuf# = std.mksb()
31         var since_nl : int = 0
32         var buf : byte[3] = [0, 0, 0]
33         var four_pos : int = 0
34         var num_equals : int = 0
36         for b : encoded
37                 if b == ('\n' : byte) || b == ('\r' : byte)
38                         since_nl = 0
39                         continue
40                 elif since_nl > 76
41                         goto not_base64
42                 else
43                         since_nl++
44                 ;;
46                 if b == ('=' : byte)
47                         num_equals++
48                 ;;
50                 match b64_value(b)
51                 | `std.None: continue
52                 | `std.Some n:
53                         if n != 0 && num_equals != 0
54                                 goto not_base64
55                         ;;
57                         match four_pos
58                         | 0:
59                                 buf = [0, 0, 0]
60                                 buf[0] |= (n & 0b00111111) << 2
61                         | 1:
62                                 buf[0] |= (n & 0b00110000) >> 4
63                                 buf[1] |= (n & 0b00001111) << 4
64                         | 2:
65                                 buf[1] |= (n & 0b00111100) >> 2
66                                 buf[2] |= (n & 0b00000011) << 6
67                         | 3:
68                                 buf[2] |= (n & 0b00111111)
69                                 std.sbputs(decoded, buf[0:3 - num_equals])
70                         | _: goto not_base64
71                         ;;
73                         four_pos = (four_pos + 1) % 4
74                 ;;
75         ;;
77         if four_pos != 0
78                 goto not_base64
79         ;;
81         if !util.non_ctrl_utf8(std.sbpeek(decoded))
82                 goto not_base64
83         ;;
85         -> `std.Ok std.sbfin(decoded)
87 :not_base64
88         -> `std.Err void