base64_encode_bytes Subroutine

public subroutine base64_encode_bytes(bytes, nbytes, output)

Core base64 encoder (allocatable output)

Arguments

Type IntentOptional Attributes Name
integer(kind=int8), intent(in) :: bytes(:)
integer, intent(in) :: nbytes
character(len=:), intent(out), allocatable :: output

Source Code

  subroutine base64_encode_bytes(bytes, nbytes, output)
    !! Core base64 encoder (allocatable output)
    use iso_fortran_env, only: int8
    implicit none
    integer(int8), intent(in) :: bytes(:)
    integer, intent(in) :: nbytes
    character(:), allocatable, intent(out) :: output

    character(64), parameter :: b64 = &
         'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    integer :: i, j, ngroups, out_len
    integer :: b0, b1, b2, idx

    ngroups = (nbytes + 2) / 3
    out_len = ngroups * 4
    allocate(character(out_len) :: output)

    j = 1
    do i = 1, nbytes, 3
       b0 = iand(int(bytes(i)), 255)
       if(i + 1 .le. nbytes)then
          b1 = iand(int(bytes(i+1)), 255)
       else
          b1 = 0
       end if
       if(i + 2 .le. nbytes)then
          b2 = iand(int(bytes(i+2)), 255)
       else
          b2 = 0
       end if

       idx = ishft(b0, -2) + 1
       output(j:j) = b64(idx:idx)

       idx = ior(ishft(iand(b0, 3), 4), ishft(b1, -4)) + 1
       output(j+1:j+1) = b64(idx:idx)

       if(i + 1 .le. nbytes)then
          idx = ior(ishft(iand(b1, 15), 2), ishft(b2, -6)) + 1
          output(j+2:j+2) = b64(idx:idx)
       else
          output(j+2:j+2) = '='
       end if

       if(i + 2 .le. nbytes)then
          idx = iand(b2, 63) + 1
          output(j+3:j+3) = b64(idx:idx)
       else
          output(j+3:j+3) = '='
       end if

       j = j + 4
    end do

  end subroutine base64_encode_bytes