Goでbase64エンコードを実装する

base64を自分の理解のために実装してみる。

手順はこちらの記事がわかりやすいです。RFCで読むならこちら

実装したコードは以下の通りです。ほとんど標準パッケージ

package main

import (
    "fmt"
    "os"
)

const encodeStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
const padding = '='

func main() {
    if len(os.Args) != 2 {
        panic("Invalid arguments")
    }
    input := os.Args[1]

    result := decode(input)
    fmt.Println("Result: ", result)
}

func decode(input string) string {
    src := []byte(input)
    dst := make([]byte, (len(src)+2)/3*4)

    si, di := 0, 0
    n := (len(src) / 3) * 3
    for si < n {
        v := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])

        dst[di+0] = encodeStr[v>>18&0x3F]
        dst[di+1] = encodeStr[v>>12&0x3F]
        dst[di+2] = encodeStr[v>>6&0x3F]
        dst[di+3] = encodeStr[v&0x3F]

        si += 3
        di += 4
    }

    remain := len(src) - si
    if remain == 0 {
        return string(dst)
    }

    v := uint(src[si+0]) << 16
    if remain == 2 {
        v |= uint(src[si+1]) << 8
    }

    dst[di+0] = encodeStr[v>>18&0x3F]
    dst[di+1] = encodeStr[v>>12&0x3F]

    switch remain {
    case 1:
        dst[di+2] = byte(padding)
        dst[di+3] = byte(padding)
    case 2:
        dst[di+2] = encodeStr[v>>6&0x3F]
        dst[di+3] = byte(padding)
    }

    return string(dst)
}

まとめ

  • コードを書いてみると、base64エンコードされたときに末尾に追加される=は最大で2つ、ということもわかる。
  • ビット演算とか普段使わないから勉強になる。