aboutsummaryrefslogtreecommitdiff
path: root/lib/base64.nom
blob: 01d4f2fe19cefb83d91cf9fcadb9f56f5184611f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env nomsu -V4.10.12.7
#
    This file defines actions for encoding/decoding base 64, as specified in:
    https://tools.ietf.org/html/rfc4648
    
%b64_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
%reverse_b64 = {: for %i in 1 to (size of %b64_str): add %b64_str.%i = (%i - 1)}
%reverse_b64."=" = 0
test:
    %cases = ["", "Zg==", "Zm8=", "Zm9v", "Zm9vYg==", "Zm9vYmE=", "Zm9vYmFy"]
    for %len = %encoded in %cases:
        %plain = "foobar".[1, %len - 1]
        assume (base64 %plain) == %encoded
        assume (base64 decode %encoded) == %plain

externally [base64 %str, base64 encode %str, %str base64] all mean:
    %chars = []
    for %i in 1 to (size of %str) via 3:
        %bytes = [=lua "\%str:byte(\%i, \(%i + 2))"]
        %chars::add %b64_str.(((%bytes.1 & 252) >> 2) + 1)
        if (size of %bytes) is:
            3:
                %chars::add %b64_str.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
                %chars::add %b64_str.(((%bytes.2 & 15) << 2) + ((%bytes.3 & 192) >> 6) + 1)
                %chars::add %b64_str.((%bytes.3 & 63) + 1)
            
            2:
                %chars::add %b64_str.(((%bytes.1 & 3) << 4) + ((%bytes.2 & 240) >> 4) + 1)
                %chars::add %b64_str.(((%bytes.2 & 15) << 2) + 1)
                %chars::add "="
            
            1:
                %chars::add %b64_str.(((%bytes.1 & 3) << 4) + 1)
                %chars::add "="
                %chars::add "="
    return (%chars::joined)

externally (chr %) means (=lua "string.char(\%)")
externally [decode base64 %str, %str base64 decoded, base64 decode %str] all mean:
    %chars = []
    for %i in 1 to (size of %str) via 4:
        %indices = [: for % in %i to (%i + 3): add %reverse_b64.(%str.%)]
        %chars::add (chr ((%indices.1 << 2) + ((%indices.2 & 48) >> 4)))
        if (%str.(%i + 2) == "="): stop
        %chars::add (chr (((%indices.2 & 15) << 4) + ((%indices.3 & 60) >> 2)))
        if (%str.(%i + 3) == "="): stop
        %chars::add (chr (((%indices.3 & 3) << 6) + %indices.4))
    return (%chars::joined)