; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: OS independent string manipulation library.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: Author of this library is Decard (Mateusz Tymek)
;
;_________________________________________________________________________________________

module "Base64 library"

if used base64_table
  base64_table db "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
               db "abcdefghijklmnopqrstuvwxyz"
               db "0123456789+/"
end if


; calculates size of base64 stream after encoding

proc Base64Size, .DataLen
begin
        push    ebx ecx edx

        mov     eax, [.DataLen]
        mov     ebx, eax
        add     eax, 2

        xor     edx, edx

        mov     ecx, 3
        div     ecx

        add     ebx, 3

        sub     ebx, edx

        mov     eax, ebx

        xor     edx, edx
        div     ecx
        shl     eax, 2

        pop     edx ecx ebx
        return
endp


; encodes given buffer into base64 stream

proc EncodeBase64, .pData, .Length
begin
        push    ecx edx esi edi

        mov     esi, [.pData]
        mov     ecx, [.Length]

        stdcall StrNew
        mov     edi, eax

        stdcall Base64Size, ecx
        stdcall StrSetCapacity, edi, eax

        push    edi

        stdcall StrPtr, edi
        mov     edi, eax

        push    edi

.loop:
        mov     edx, [esi]
        cmp     ecx, 3
        jae     .remainder_ok
        and     edx, 0xffff
        cmp     ecx, 2
        jae     .remainder_ok
        and     edx, 0xff

.remainder_ok:
        bswap   edx

        mov     eax, edx
        shr     eax, 26
        and     eax, 111111b
        mov     al, [base64_table+eax]
        mov     [edi], al
        inc     edi

        mov     eax, edx
        shr     eax, 20
        and     eax, 111111b
        mov     al, [base64_table+eax]
        mov     [edi], al
        inc     edi
        dec     ecx
        jz      .r2

        mov     eax, edx
        shr     eax, 14
        and     eax, 111111b
        mov     al, [base64_table+eax]
        mov     [edi], al
        inc     edi
        dec     ecx
        jz      .r1

        mov     eax, edx
        shr     eax, 8
        and     eax, 111111b
        mov     al, [base64_table+eax]
        mov     [edi], al
        inc     edi

        add     esi, 3
        dec     ecx
        jnz     .loop
        jmp     .finish

.r2:
        mov     byte [edi], '-'
        inc     edi

.r1:
        mov     byte [edi], '-'
        inc     edi

.finish:
        mov     byte [edi], 0

        mov     ecx, edi
        pop     edi

        sub     ecx, edi    ; string length.
        mov     [edi+string.len], ecx

        pop     eax             ; string handle

        pop     edi esi edx ecx
        return
endp





; decodes base64 stream into given buffer

proc DecodeBase64, .hString
.decode_table rb 0x100
.ret          dd ?
begin
        push    ebx ecx edx esi edi

        xor     eax, eax
        mov     ebx, 63

.make_table:
        mov     al, [base64_table+ebx]
        mov     [.decode_table+eax], bl
        dec     ebx
        jns     .make_table

        mov     [.decode_table+'-'], 0

        stdcall StrPtr, [.hString]
        mov     esi, eax

        stdcall StrLen, [.hString]
        mov     ecx, eax

        lea     eax, [ecx+4]
        stdcall GetMem, eax
        lea     edi, [eax+4]
        mov     [.ret], edi

        xor     ebx, ebx
        xor     eax, eax

.load_dword:
        mov     edx, [esi]
        bswap   edx
        add     esi, 4
        mov     al, dl
        mov     al, [.decode_table+eax]
        shrd    ebx, eax, 6
        shr     edx, 8
        mov     al, dl
        mov     al, [.decode_table+eax]
        shrd    ebx, eax, 6
        shr     edx, 8
        mov     al, dl
        mov     al, [.decode_table+eax]
        shrd    ebx, eax, 6
        shr     edx, 8
        mov     al, dl
        mov     al, [.decode_table+eax]
        shrd    ebx, eax, 6
        bswap   ebx

        mov     [edi], ebx
        add     edi, 3
        sub     ecx, 4
        js      .exit_loop      ; this jump should be never taken
        jnz     .load_dword     ; (src_size should be a multiple of four)

.exit_loop:
        sub     edi, 2
        cmp     byte [edi], 0
        je      .size_ok

        inc     edi
        cmp     byte [edi], 0
        je      .size_ok

        inc     edi

.size_ok:
        mov     eax, [.ret]
        sub     edi, eax
        mov     [eax-4], edi

        pop     edi esi edx ecx ebx
        return
endp



endmodule