-
Notifications
You must be signed in to change notification settings - Fork 0
/
base64.go
92 lines (69 loc) · 1.76 KB
/
base64.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package jq
import (
"encoding/base64"
"nikand.dev/go/json"
)
type (
// Base64 reads decoded string, encodes it into base64 format, and returns it as a string.
Base64 struct {
*base64.Encoding
Buf []byte
}
// Base64d reads decoded string, decodes if from base64 format, and returns it as a string.
Base64d struct {
*base64.Encoding
Buf []byte
}
)
func (f *Base64) Next(w, r []byte, st int, _ State) (_ []byte, i int, _ State, err error) {
w, f.Buf, i, err = base64Apply(w, r, st, f.Encoding, true, f.Buf[:0])
return w, i, nil, err
}
func (f *Base64d) Next(w, r []byte, st int, _ State) (_ []byte, i int, _ State, err error) {
w, f.Buf, i, err = base64Apply(w, r, st, f.Encoding, false, f.Buf[:0])
return w, i, nil, err
}
func base64Apply(w, r []byte, st int, e *base64.Encoding, enc bool, buf []byte) (res, buf1 []byte, i int, err error) {
var p json.Decoder
st = p.SkipSpaces(r, st)
if st == len(r) {
return w, buf, st, nil
}
s, i, err := p.DecodeString(r, st, buf)
if err != nil {
return w, s, i, pe(err, i)
}
if e == nil {
e = base64.StdEncoding
}
if enc {
n := e.EncodedLen(len(s))
wst := len(w) + 1 // open "
w = grow(w, n+2)
e.Encode(w[wst:], s)
w[wst-1] = '"'
w[len(w)-1] = '"'
} else {
n := e.DecodedLen(len(s))
ssize := len(s)
s = grow(s, ssize+n)
n, err = e.Decode(s[ssize:], s[:ssize])
// log.Printf("decoded base64 (err %v): %q -> %q", err, s[:ssize], s[ssize:ssize+n])
if err != nil {
return w, s, i, err
}
w = (&json.Encoder{}).EncodeString(w, s[ssize:ssize+n])
}
return w, s, i, nil
}
func grow(b []byte, size int) []byte {
if size-cap(b) >= 4*1024 {
q := make([]byte, size)
copy(q, b)
return q
}
for size > cap(b) {
b = append(b[:cap(b)], 0, 0, 0, 0, 0, 0, 0, 0)
}
return b[:size]
}