aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding/base64
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
commitaf146490bb04205107cb23e301ec7a8ff927b5fc (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/encoding/base64
parent725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff)
downloadgcc-af146490bb04205107cb23e301ec7a8ff927b5fc.zip
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.bz2
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 From-SVN: r229616
Diffstat (limited to 'libgo/go/encoding/base64')
-rw-r--r--libgo/go/encoding/base64/base64.go225
-rw-r--r--libgo/go/encoding/base64/base64_test.go74
2 files changed, 202 insertions, 97 deletions
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index ad3abe6..3302fb4 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -6,10 +6,8 @@
package base64
import (
- "bytes"
"io"
"strconv"
- "strings"
)
/*
@@ -22,18 +20,32 @@ import (
// (RFC 1421). RFC 4648 also defines an alternate encoding, which is
// the standard encoding with - and _ substituted for + and /.
type Encoding struct {
- encode string
+ encode [64]byte
decodeMap [256]byte
+ padChar rune
}
+const (
+ StdPadding rune = '=' // Standard padding character
+ NoPadding rune = -1 // No padding
+)
+
const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
-// NewEncoding returns a new Encoding defined by the given alphabet,
+// NewEncoding returns a new padded Encoding defined by the given alphabet,
// which must be a 64-byte string.
+// The resulting Encoding uses the default padding character ('='),
+// which may be changed or disabled via WithPadding.
func NewEncoding(encoder string) *Encoding {
+ if len(encoder) != 64 {
+ panic("encoding alphabet is not 64-bytes long")
+ }
+
e := new(Encoding)
- e.encode = encoder
+ e.padChar = StdPadding
+ copy(e.encode[:], encoder)
+
for i := 0; i < len(e.decodeMap); i++ {
e.decodeMap[i] = 0xFF
}
@@ -43,6 +55,13 @@ func NewEncoding(encoder string) *Encoding {
return e
}
+// WithPadding creates a new encoding identical to enc except
+// with a specified padding character, or NoPadding to disable padding.
+func (enc Encoding) WithPadding(padding rune) *Encoding {
+ enc.padChar = padding
+ return &enc
+}
+
// StdEncoding is the standard base64 encoding, as defined in
// RFC 4648.
var StdEncoding = NewEncoding(encodeStd)
@@ -51,12 +70,15 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in URLs and file names.
var URLEncoding = NewEncoding(encodeURL)
-var removeNewlinesMapper = func(r rune) rune {
- if r == '\r' || r == '\n' {
- return -1
- }
- return r
-}
+// RawStdEncoding is the standard raw, unpadded base64 encoding,
+// as defined in RFC 4648 section 3.2.
+// This is the same as StdEncoding but omits padding characters.
+var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
+
+// URLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
+// It is typically used in URLs and file names.
+// This is the same as URLEncoding but omits padding characters.
+var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
/*
* Encoder
@@ -73,42 +95,45 @@ func (enc *Encoding) Encode(dst, src []byte) {
return
}
- for len(src) > 0 {
- var b0, b1, b2, b3 byte
+ di, si := 0, 0
+ n := (len(src) / 3) * 3
+ for si < n {
+ // Convert 3x 8bit source bytes into 4 bytes
+ val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
- // Unpack 4x 6-bit source blocks into a 4 byte
- // destination quantum
- switch len(src) {
- default:
- b3 = src[2] & 0x3F
- b2 = src[2] >> 6
- fallthrough
- case 2:
- b2 |= (src[1] << 2) & 0x3F
- b1 = src[1] >> 4
- fallthrough
- case 1:
- b1 |= (src[0] << 4) & 0x3F
- b0 = src[0] >> 2
- }
+ dst[di+0] = enc.encode[val>>18&0x3F]
+ dst[di+1] = enc.encode[val>>12&0x3F]
+ dst[di+2] = enc.encode[val>>6&0x3F]
+ dst[di+3] = enc.encode[val&0x3F]
- // Encode 6-bit blocks using the base64 alphabet
- dst[0] = enc.encode[b0]
- dst[1] = enc.encode[b1]
- dst[2] = enc.encode[b2]
- dst[3] = enc.encode[b3]
-
- // Pad the final quantum
- if len(src) < 3 {
- dst[3] = '='
- if len(src) < 2 {
- dst[2] = '='
- }
- break
- }
+ si += 3
+ di += 4
+ }
+
+ remain := len(src) - si
+ if remain == 0 {
+ return
+ }
+ // Add the remaining small block
+ val := uint(src[si+0]) << 16
+ if remain == 2 {
+ val |= uint(src[si+1]) << 8
+ }
+
+ dst[di+0] = enc.encode[val>>18&0x3F]
+ dst[di+1] = enc.encode[val>>12&0x3F]
- src = src[3:]
- dst = dst[4:]
+ switch remain {
+ case 2:
+ dst[di+2] = enc.encode[val>>6&0x3F]
+ if enc.padChar != NoPadding {
+ dst[di+3] = byte(enc.padChar)
+ }
+ case 1:
+ if enc.padChar != NoPadding {
+ dst[di+2] = byte(enc.padChar)
+ dst[di+3] = byte(enc.padChar)
+ }
}
}
@@ -145,8 +170,8 @@ func (e *encoder) Write(p []byte) (n int, err error) {
if e.nbuf < 3 {
return
}
- e.enc.Encode(e.out[0:], e.buf[0:])
- if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
+ e.enc.Encode(e.out[:], e.buf[:])
+ if _, e.err = e.w.Write(e.out[:4]); e.err != nil {
return n, e.err
}
e.nbuf = 0
@@ -159,7 +184,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn = len(p)
nn -= nn % 3
}
- e.enc.Encode(e.out[0:], p[0:nn])
+ e.enc.Encode(e.out[:], p[:nn])
if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
return n, e.err
}
@@ -181,9 +206,9 @@ func (e *encoder) Write(p []byte) (n int, err error) {
func (e *encoder) Close() error {
// If there's anything left in the buffer, flush it out
if e.err == nil && e.nbuf > 0 {
- e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+ e.enc.Encode(e.out[:], e.buf[:e.nbuf])
+ _, e.err = e.w.Write(e.out[:e.enc.EncodedLen(e.nbuf)])
e.nbuf = 0
- _, e.err = e.w.Write(e.out[0:4])
}
return e.err
}
@@ -199,7 +224,12 @@ func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
// EncodedLen returns the length in bytes of the base64 encoding
// of an input buffer of length n.
-func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
+func (enc *Encoding) EncodedLen(n int) int {
+ if enc.padChar == NoPadding {
+ return (n*8 + 5) / 6 // minimum # chars at 6 bits per char
+ }
+ return (n + 2) / 3 * 4 // minimum # 4-char quanta, 3 bytes each
+}
/*
* Decoder
@@ -212,66 +242,86 @@ func (e CorruptInputError) Error() string {
}
// decode is like Decode but returns an additional 'end' value, which
-// indicates if end-of-message padding was encountered and thus any
-// additional data is an error. This method assumes that src has been
-// stripped of all supported whitespace ('\r' and '\n').
+// indicates if end-of-message padding or a partial quantum was encountered
+// and thus any additional data is an error.
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- olen := len(src)
- for len(src) > 0 && !end {
+ si := 0
+
+ // skip over newlines
+ for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+ si++
+ }
+
+ for si < len(src) && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
- dlen := 4
+ dinc, dlen := 3, 4
for j := range dbuf {
- if len(src) == 0 {
- return n, false, CorruptInputError(olen - len(src) - j)
+ if len(src) == si {
+ if enc.padChar != NoPadding || j < 2 {
+ return n, false, CorruptInputError(si - j)
+ }
+ dinc, dlen, end = j-1, j, true
+ break
}
- in := src[0]
- src = src[1:]
- if in == '=' {
+ in := src[si]
+
+ si++
+ // skip over newlines
+ for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+ si++
+ }
+
+ if rune(in) == enc.padChar {
// We've reached the end and there's padding
switch j {
case 0, 1:
// incorrect padding
- return n, false, CorruptInputError(olen - len(src) - 1)
+ return n, false, CorruptInputError(si - 1)
case 2:
// "==" is expected, the first "=" is already consumed.
- if len(src) == 0 {
+ if si == len(src) {
// not enough padding
- return n, false, CorruptInputError(olen)
+ return n, false, CorruptInputError(len(src))
}
- if src[0] != '=' {
+ if rune(src[si]) != enc.padChar {
// incorrect padding
- return n, false, CorruptInputError(olen - len(src) - 1)
+ return n, false, CorruptInputError(si - 1)
+ }
+
+ si++
+ // skip over newlines
+ for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+ si++
}
- src = src[1:]
}
- if len(src) > 0 {
+ if si < len(src) {
// trailing garbage
- err = CorruptInputError(olen - len(src))
+ err = CorruptInputError(si)
}
- dlen, end = j, true
+ dinc, dlen, end = 3, j, true
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(olen - len(src) - 1)
+ return n, false, CorruptInputError(si - 1)
}
}
- // Pack 4x 6-bit source blocks into 3 byte destination
- // quantum
+ // Convert 4x 6bit source bytes into 3 bytes
+ val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
switch dlen {
case 4:
- dst[2] = dbuf[2]<<6 | dbuf[3]
+ dst[2] = byte(val >> 0)
fallthrough
case 3:
- dst[1] = dbuf[1]<<4 | dbuf[2]>>2
+ dst[1] = byte(val >> 8)
fallthrough
case 2:
- dst[0] = dbuf[0]<<2 | dbuf[1]>>4
+ dst[0] = byte(val >> 16)
}
- dst = dst[3:]
+ dst = dst[dinc:]
n += dlen - 1
}
@@ -284,14 +334,12 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// number of bytes successfully written and CorruptInputError.
// New line characters (\r and \n) are ignored.
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
- src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base64 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
- s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, _, err := enc.decode(dbuf, []byte(s))
return dbuf[:n], err
@@ -320,6 +368,8 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, nil
}
+ // This code assumes that d.r strips supported whitespace ('\r' and '\n').
+
// Read a chunk.
nn := len(p) / 3 * 4
if nn < 4 {
@@ -338,12 +388,12 @@ func (d *decoder) Read(p []byte) (n int, err error) {
nr := d.nbuf / 4 * 4
nw := d.nbuf / 4 * 3
if nw > len(p) {
- nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
- d.out = d.outbuf[0:nw]
+ nw, d.end, d.err = d.enc.decode(d.outbuf[:], d.buf[:nr])
+ d.out = d.outbuf[:nw]
n = copy(p, d.out)
d.out = d.out[n:]
} else {
- n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+ n, d.end, d.err = d.enc.decode(p, d.buf[:nr])
}
d.nbuf -= nr
for i := 0; i < d.nbuf; i++ {
@@ -364,7 +414,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) {
n, err := r.wrapped.Read(p)
for n > 0 {
offset := 0
- for i, b := range p[0:n] {
+ for i, b := range p[:n] {
if b != '\r' && b != '\n' {
if i != offset {
p[offset] = b
@@ -388,4 +438,11 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
// DecodedLen returns the maximum length in bytes of the decoded data
// corresponding to n bytes of base64-encoded data.
-func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
+func (enc *Encoding) DecodedLen(n int) int {
+ if enc.padChar == NoPadding {
+ // Unpadded data may end with partial block of 2-3 characters.
+ return (n*6 + 7) / 8
+ }
+ // Padded base64 should always be a multiple of 4 characters in length.
+ return n / 4 * 3
+}
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index 7d199bf..d144b96 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -45,6 +45,48 @@ var pairs = []testpair{
{"sure.", "c3VyZS4="},
}
+// Do nothing to a reference base64 string (leave in standard format)
+func stdRef(ref string) string {
+ return ref
+}
+
+// Convert a reference string to URL-encoding
+func urlRef(ref string) string {
+ ref = strings.Replace(ref, "+", "-", -1)
+ ref = strings.Replace(ref, "/", "_", -1)
+ return ref
+}
+
+// Convert a reference string to raw, unpadded format
+func rawRef(ref string) string {
+ return strings.TrimRight(ref, "=")
+}
+
+// Both URL and unpadding conversions
+func rawUrlRef(ref string) string {
+ return rawRef(urlRef(ref))
+}
+
+// A nonstandard encoding with a funny padding character, for testing
+var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@'))
+
+func funnyRef(ref string) string {
+ return strings.Replace(ref, "=", "@", -1)
+}
+
+type encodingTest struct {
+ enc *Encoding // Encoding to test
+ conv func(string) string // Reference string converter
+}
+
+var encodingTests = []encodingTest{
+ encodingTest{StdEncoding, stdRef},
+ encodingTest{URLEncoding, urlRef},
+ encodingTest{RawStdEncoding, rawRef},
+ encodingTest{RawURLEncoding, rawUrlRef},
+ encodingTest{funnyEncoding, funnyRef},
+}
+
var bigtest = testpair{
"Twas brillig, and the slithy toves",
"VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
@@ -60,8 +102,11 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
func TestEncode(t *testing.T) {
for _, p := range pairs {
- got := StdEncoding.EncodeToString([]byte(p.decoded))
- testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
+ for _, tt := range encodingTests {
+ got := tt.enc.EncodeToString([]byte(p.decoded))
+ testEqual(t, "Encode(%q) = %q, want %q", p.decoded,
+ got, tt.conv(p.encoded))
+ }
}
}
@@ -97,18 +142,21 @@ func TestEncoderBuffering(t *testing.T) {
func TestDecode(t *testing.T) {
for _, p := range pairs {
- dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
- count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
- testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
- testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
- if len(p.encoded) > 0 {
- testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
- }
- testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+ for _, tt := range encodingTests {
+ encoded := tt.conv(p.encoded)
+ dbuf := make([]byte, tt.enc.DecodedLen(len(encoded)))
+ count, end, err := tt.enc.decode(dbuf, []byte(encoded))
+ testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil))
+ testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded))
+ if len(encoded) > 0 {
+ testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0)
+ }
+ testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded)
- dbuf, err = StdEncoding.DecodeString(p.encoded)
- testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
- testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+ dbuf, err = tt.enc.DecodeString(encoded)
+ testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil))
+ testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+ }
}
}