diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
commit | af146490bb04205107cb23e301ec7a8ff927b5fc (patch) | |
tree | 13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/encoding/base64 | |
parent | 725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff) | |
download | gcc-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.go | 225 | ||||
-rw-r--r-- | libgo/go/encoding/base64/base64_test.go | 74 |
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) + } } } |