148 lines
3.0 KiB
Plaintext
148 lines
3.0 KiB
Plaintext
## vim: set sw=3 expandtab:
|
|
|
|
# ( ... get_char store_byte -- end_char )
|
|
# get_char: ( ... -- ... char )
|
|
# store_byte: ( ... byte -- ... )
|
|
decode_base64:
|
|
push
|
|
push
|
|
immed 0
|
|
immed 0
|
|
.loop: # ( n bits // gc sb )
|
|
rdup
|
|
pop
|
|
swap
|
|
push
|
|
swap
|
|
push # ( gc // n bits gc sb )
|
|
call # ( ch // n bits gc sb )
|
|
dup; immed 10; sub
|
|
jump .not_nl rel ne drop
|
|
drop
|
|
pop
|
|
pop
|
|
jump .loop # ( n bits // gc sb )
|
|
.not_nl: # ( ch // n bits gc sb )
|
|
dup; immed '='; sub
|
|
jump .pad rel eq drop
|
|
dup
|
|
call decode_char # ( ch val // n bits gc sb )
|
|
jump .invalid rel lt
|
|
nip # ( val // n bits gc sb )
|
|
pop
|
|
swap
|
|
pop # ( n val bits // gc sb )
|
|
or
|
|
immed -6
|
|
rshift # ( n bits' // gc sb ) [ bits' = (bits|val)<<6 ]
|
|
push
|
|
immed 6
|
|
add # ( n' // bits' gc sb ) [ n' = n + 6 ]
|
|
dup; immed 8; sub
|
|
jump .store rel ge # ( n' (n'-8) // bits' gc sb )
|
|
drop
|
|
pop
|
|
jump .loop rel # ( n' bits' // gc sb )
|
|
.store: # ( n' (n'-8) // bits' gc sb )
|
|
nip
|
|
dup # ( n'' (n'-8) // bits' gc sb ) [ n'' = n'-8 ]
|
|
rdup
|
|
pop
|
|
swap # ( n'' bits' (n'-8) // bits' gc sb )
|
|
immed 6
|
|
add
|
|
rshift # ( n'' byte // bits' gc sb )
|
|
swap
|
|
pop
|
|
pop
|
|
rdup
|
|
pop # ( byte n'' bits' gc sb // sb )
|
|
swap
|
|
push
|
|
swap
|
|
push
|
|
swap
|
|
push # ( byte sb // n'' bits' gc sb )
|
|
call # ( // n'' bits' gc sb )
|
|
pop
|
|
pop
|
|
jump .loop # ( n'' bits' // gc sb )
|
|
.pad: # ( ch // n bits gc sb )
|
|
# reset accumulated state
|
|
drop
|
|
rdrop
|
|
rdrop
|
|
immed 0
|
|
immed 0
|
|
# continue until something non-base64 is received
|
|
jump .loop # ( n bits // gc sb )
|
|
.invalid: # ( ch val // n bits gc sb )
|
|
drop
|
|
rdrop
|
|
rdrop
|
|
rdrop
|
|
rdrop
|
|
return # ( ch // )
|
|
|
|
# ( val low high -- (low<=val<=high) )
|
|
in_range:
|
|
over
|
|
sub
|
|
push # ( val low // (high-low) )
|
|
sub
|
|
jump .too_low rel lt
|
|
pop # ( (val-low) (high-low) // )
|
|
sub
|
|
jump .too_high rel gt drop
|
|
immed 1
|
|
return
|
|
.too_low: # ( (val-low) // (high-low) )
|
|
drop
|
|
rdrop
|
|
.too_high:
|
|
immed 0
|
|
return
|
|
|
|
decode_char:
|
|
dup; immed 'A'; immed 'Z'
|
|
call in_range
|
|
jump .uc rel ne drop
|
|
|
|
dup; immed 'a'; immed 'z'
|
|
call in_range
|
|
jump .lc rel ne drop
|
|
|
|
dup; immed '0'; immed '9'
|
|
call in_range
|
|
jump .digit rel ne drop
|
|
|
|
dup; immed '+'; sub
|
|
jump .plus rel eq drop
|
|
|
|
dup; immed '/'; sub
|
|
jump .slash rel eq drop
|
|
|
|
.invalid:
|
|
immed -1
|
|
nip return
|
|
|
|
.uc:
|
|
immed 65 # 'A' == 65, base64['A'] == 0
|
|
sub return
|
|
|
|
.lc:
|
|
immed 71 # 'a' == 97, base64['a'] == 26
|
|
sub return
|
|
|
|
.digit:
|
|
immed 4 # '0' == 48, base64['0'] == 52
|
|
add return
|
|
|
|
.plus:
|
|
immed 62
|
|
nip return
|
|
|
|
.slash:
|
|
immed 63
|
|
nip return
|