1package base64vlq
2
3import "io"
4
5const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
6
7const (
8	vlqBaseShift       = 5
9	vlqBase            = 1 << vlqBaseShift
10	vlqBaseMask        = vlqBase - 1
11	vlqSignBit         = 1
12	vlqContinuationBit = vlqBase
13)
14
15var decodeMap [256]byte
16
17func init() {
18	for i := 0; i < len(encodeStd); i++ {
19		decodeMap[encodeStd[i]] = byte(i)
20	}
21}
22
23func toVLQSigned(n int32) int32 {
24	if n < 0 {
25		return -n<<1 + 1
26	}
27	return n << 1
28}
29
30func fromVLQSigned(n int32) int32 {
31	isNeg := n&vlqSignBit != 0
32	n >>= 1
33	if isNeg {
34		return -n
35	}
36	return n
37}
38
39type Encoder struct {
40	w io.ByteWriter
41}
42
43func NewEncoder(w io.ByteWriter) *Encoder {
44	return &Encoder{
45		w: w,
46	}
47}
48
49func (enc Encoder) Encode(n int32) error {
50	n = toVLQSigned(n)
51	for digit := int32(vlqContinuationBit); digit&vlqContinuationBit != 0; {
52		digit = n & vlqBaseMask
53		n >>= vlqBaseShift
54		if n > 0 {
55			digit |= vlqContinuationBit
56		}
57
58		err := enc.w.WriteByte(encodeStd[digit])
59		if err != nil {
60			return err
61		}
62	}
63	return nil
64}
65
66type Decoder struct {
67	r io.ByteReader
68}
69
70func NewDecoder(r io.ByteReader) Decoder {
71	return Decoder{
72		r: r,
73	}
74}
75
76func (dec Decoder) Decode() (n int32, err error) {
77	shift := uint(0)
78	for continuation := true; continuation; {
79		c, err := dec.r.ReadByte()
80		if err != nil {
81			return 0, err
82		}
83
84		c = decodeMap[c]
85		continuation = c&vlqContinuationBit != 0
86		n += int32(c&vlqBaseMask) << shift
87		shift += vlqBaseShift
88	}
89	return fromVLQSigned(n), nil
90}
91