96 lines
1.5 KiB
Go
96 lines
1.5 KiB
Go
|
package base64vlq
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
)
|
||
|
|
||
|
const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||
|
|
||
|
const (
|
||
|
vlqBaseShift = 5
|
||
|
vlqBase = 1 << vlqBaseShift
|
||
|
vlqBaseMask = vlqBase - 1
|
||
|
vlqSignBit = 1
|
||
|
vlqContinuationBit = vlqBase
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
decodeMap [256]int
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
for i := 0; i < len(encodeStd); i++ {
|
||
|
decodeMap[encodeStd[i]] = i
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func toVLQSigned(n int) int {
|
||
|
if n < 0 {
|
||
|
return -n<<1 + 1
|
||
|
} else {
|
||
|
return n << 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func fromVLQSigned(n int) int {
|
||
|
isNeg := n&vlqSignBit != 0
|
||
|
n >>= 1
|
||
|
if isNeg {
|
||
|
return -n
|
||
|
}
|
||
|
return n
|
||
|
}
|
||
|
|
||
|
type Encoder struct {
|
||
|
w io.ByteWriter
|
||
|
}
|
||
|
|
||
|
func NewEncoder(w io.ByteWriter) *Encoder {
|
||
|
return &Encoder{
|
||
|
w: w,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (enc *Encoder) Encode(n int) error {
|
||
|
n = toVLQSigned(n)
|
||
|
for digit := vlqContinuationBit; digit&vlqContinuationBit != 0; {
|
||
|
digit = n & vlqBaseMask
|
||
|
n >>= vlqBaseShift
|
||
|
if n > 0 {
|
||
|
digit |= vlqContinuationBit
|
||
|
}
|
||
|
err := enc.w.WriteByte(encodeStd[digit])
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type Decoder struct {
|
||
|
r io.ByteReader
|
||
|
}
|
||
|
|
||
|
func NewDecoder(r io.ByteReader) *Decoder {
|
||
|
return &Decoder{
|
||
|
r: r,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (dec *Decoder) Decode() (n int, err error) {
|
||
|
shift := uint(0)
|
||
|
for continuation := true; continuation; {
|
||
|
c, err := dec.r.ReadByte()
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
digit := decodeMap[c]
|
||
|
continuation = digit&vlqContinuationBit != 0
|
||
|
digit &= vlqBaseMask
|
||
|
n = n + digit<<shift
|
||
|
shift += vlqBaseShift
|
||
|
}
|
||
|
return fromVLQSigned(n), nil
|
||
|
}
|