diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-07-22 18:15:38 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-07-22 18:15:38 +0000 |
commit | 22b955cca564a9a3a5b8c9d9dd1e295b7943c128 (patch) | |
tree | abdbd898676e1f853fca2d7e031d105d7ebcf676 /libgo/go/encoding | |
parent | 9d04a3af4c6491536badf6bde9707c907e4d196b (diff) | |
download | gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.zip gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.gz gcc-22b955cca564a9a3a5b8c9d9dd1e295b7943c128.tar.bz2 |
libgo: update to go1.7rc3
Reviewed-on: https://go-review.googlesource.com/25150
From-SVN: r238662
Diffstat (limited to 'libgo/go/encoding')
45 files changed, 1135 insertions, 391 deletions
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go index 4d71938..d42eb0a 100644 --- a/libgo/go/encoding/ascii85/ascii85.go +++ b/libgo/go/encoding/ascii85/ascii85.go @@ -20,7 +20,7 @@ import ( // // The encoding handles 4-byte chunks, using a special encoding // for the last fragment, so Encode is not appropriate for use on -// individual blocks of a large data stream. Use NewEncoder() instead. +// individual blocks of a large data stream. Use NewEncoder() instead. // // Often, ascii85-encoded data is wrapped in <~ and ~> symbols. // Encode does not add these. @@ -85,7 +85,7 @@ func Encode(dst, src []byte) int { // MaxEncodedLen returns the maximum length of an encoding of n source bytes. func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 } -// NewEncoder returns a new ascii85 stream encoder. Data written to +// NewEncoder returns a new ascii85 stream encoder. Data written to // the returned writer will be encoded and then written to w. // Ascii85 encodings operate in 32-bit blocks; when finished // writing, the caller must Close the returned encoder to flush any @@ -294,7 +294,7 @@ func (d *decoder) Read(p []byte) (n int, err error) { } } - // Out of input, out of decoded output. Check errors. + // Out of input, out of decoded output. Check errors. if d.err != nil { return 0, d.err } diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go index 8bafefd..2b5ad08 100644 --- a/libgo/go/encoding/asn1/asn1.go +++ b/libgo/go/encoding/asn1/asn1.go @@ -393,7 +393,7 @@ func isPrintable(b byte) bool { // byte slice and returns it. func parseIA5String(bytes []byte) (ret string, err error) { for _, b := range bytes { - if b >= 0x80 { + if b >= utf8.RuneSelf { err = SyntaxError{"IA5String contains invalid character"} return } @@ -461,6 +461,11 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i if err != nil { return } + // Tags should be encoded in minimal form. + if ret.tag < 0x1f { + err = SyntaxError{"non-minimal tag"} + return + } } if offset >= len(bytes) { err = SyntaxError{"truncated tag or length"} diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go index e0e8331..f8623fa 100644 --- a/libgo/go/encoding/asn1/asn1_test.go +++ b/libgo/go/encoding/asn1/asn1_test.go @@ -364,7 +364,7 @@ var tagAndLengthData = []tagAndLengthTest{ {[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}}, {[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}}, {[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}}, - {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}}, + {[]byte{0x1f, 0x1f, 0x00}, true, tagAndLength{0, 31, 0, false}}, {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}}, {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}}, {[]byte{0x00, 0x81, 0x80}, true, tagAndLength{0, 0, 128, false}}, @@ -382,6 +382,8 @@ var tagAndLengthData = []tagAndLengthTest{ {[]byte{0xa0, 0x81, 0x7f}, false, tagAndLength{}}, // Tag numbers which would overflow int32 are rejected. (The value below is 2^31.) {[]byte{0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00}, false, tagAndLength{}}, + // Long tag number form may not be used for tags that fit in short form. + {[]byte{0x1f, 0x1e, 0x00}, false, tagAndLength{}}, } func TestParseTagAndLength(t *testing.T) { diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go index 6e85858..30797ef 100644 --- a/libgo/go/encoding/asn1/marshal.go +++ b/libgo/go/encoding/asn1/marshal.go @@ -17,7 +17,7 @@ import ( // A forkableWriter is an in-memory buffer that can be // 'forked' to create new forkableWriters that bracket the -// original. After +// original. After // pre, post := w.fork() // the overall sequence of bytes represented is logically w+pre+post. type forkableWriter struct { @@ -315,9 +315,9 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) { switch { case 1950 <= year && year < 2000: - err = marshalTwoDigits(out, int(year-1900)) + err = marshalTwoDigits(out, year-1900) case 2000 <= year && year < 2050: - err = marshalTwoDigits(out, int(year-2000)) + err = marshalTwoDigits(out, year-2000) default: return StructuralError{"cannot represent time as UTCTime"} } @@ -435,7 +435,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter return out.WriteByte(0) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return marshalInt64(out, int64(v.Int())) + return marshalInt64(out, v.Int()) case reflect.Struct: t := v.Type() diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go index 5a9e869..c193e65 100644 --- a/libgo/go/encoding/base32/base32.go +++ b/libgo/go/encoding/base32/base32.go @@ -17,7 +17,7 @@ import ( */ // An Encoding is a radix 32 encoding/decoding scheme, defined by a -// 32-character alphabet. The most common is the "base32" encoding +// 32-character alphabet. The most common is the "base32" encoding // introduced for SASL GSSAPI and standardized in RFC 4648. // The alternate "base32hex" encoding is used in DNSSEC. type Encoding struct { @@ -66,7 +66,7 @@ var removeNewlinesMapper = func(r rune) rune { // // The encoding pads the output to a multiple of 8 bytes, // so Encode is not appropriate for use on individual blocks -// of a large data stream. Use NewEncoder() instead. +// of a large data stream. Use NewEncoder() instead. func (enc *Encoding) Encode(dst, src []byte) { if len(src) == 0 { return @@ -208,7 +208,7 @@ func (e *encoder) Close() error { return e.err } -// NewEncoder returns a new base32 stream encoder. Data written to +// NewEncoder returns a new base32 stream encoder. Data written to // the returned writer will be encoded using enc and then written to w. // Base32 encodings operate in 5-byte blocks; when finished // writing, the caller must Close the returned encoder to flush any @@ -313,9 +313,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { return n, end, nil } -// Decode decodes src using the encoding enc. It writes at most +// Decode decodes src using the encoding enc. It writes at most // DecodedLen(len(src)) bytes to dst and returns the number of bytes -// written. If src contains invalid base32 data, it will return the +// written. If src contains invalid base32 data, it will return the // 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) { diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go index 5a68f06..66a48a3 100644 --- a/libgo/go/encoding/base32/base32_test.go +++ b/libgo/go/encoding/base32/base32_test.go @@ -171,7 +171,7 @@ func TestDecodeCorrupt(t *testing.T) { _, err := StdEncoding.Decode(dbuf, []byte(tc.input)) if tc.offset == -1 { if err != nil { - t.Error("Decoder wrongly detected coruption in", tc.input) + t.Error("Decoder wrongly detected corruption in", tc.input) } continue } diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go index 1bda804..c2116d8 100644 --- a/libgo/go/encoding/base64/base64.go +++ b/libgo/go/encoding/base64/base64.go @@ -15,7 +15,7 @@ import ( */ // An Encoding is a radix 64 encoding/decoding scheme, defined by a -// 64-character alphabet. The most common encoding is the "base64" +// 64-character alphabet. The most common encoding is the "base64" // encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM // (RFC 1421). RFC 4648 also defines an alternate encoding, which is // the standard encoding with - and _ substituted for + and /. @@ -89,7 +89,7 @@ var RawURLEncoding = URLEncoding.WithPadding(NoPadding) // // The encoding pads the output to a multiple of 4 bytes, // so Encode is not appropriate for use on individual blocks -// of a large data stream. Use NewEncoder() instead. +// of a large data stream. Use NewEncoder() instead. func (enc *Encoding) Encode(dst, src []byte) { if len(src) == 0 { return @@ -213,7 +213,7 @@ func (e *encoder) Close() error { return e.err } -// NewEncoder returns a new base64 stream encoder. Data written to +// NewEncoder returns a new base64 stream encoder. Data written to // the returned writer will be encoded using enc and then written to w. // Base64 encodings operate in 4-byte blocks; when finished // writing, the caller must Close the returned encoder to flush any @@ -328,9 +328,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { return n, end, err } -// Decode decodes src using the encoding enc. It writes at most +// Decode decodes src using the encoding enc. It writes at most // DecodedLen(len(src)) bytes to dst and returns the number of bytes -// written. If src contains invalid base64 data, it will return the +// written. If src contains invalid base64 data, it will return the // 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) { @@ -459,7 +459,7 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader { 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 + return n * 6 / 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 fc6a1ea..19ddb92 100644 --- a/libgo/go/encoding/base64/base64_test.go +++ b/libgo/go/encoding/base64/base64_test.go @@ -221,7 +221,7 @@ func TestDecodeCorrupt(t *testing.T) { _, err := StdEncoding.Decode(dbuf, []byte(tc.input)) if tc.offset == -1 { if err != nil { - t.Error("Decoder wrongly detected coruption in", tc.input) + t.Error("Decoder wrongly detected corruption in", tc.input) } continue } @@ -234,6 +234,51 @@ func TestDecodeCorrupt(t *testing.T) { } } +func TestEncodedLen(t *testing.T) { + for _, tt := range []struct { + enc *Encoding + n int + want int + }{ + {RawStdEncoding, 0, 0}, + {RawStdEncoding, 1, 2}, + {RawStdEncoding, 2, 3}, + {RawStdEncoding, 3, 4}, + {RawStdEncoding, 7, 10}, + {StdEncoding, 0, 0}, + {StdEncoding, 1, 4}, + {StdEncoding, 2, 4}, + {StdEncoding, 3, 4}, + {StdEncoding, 4, 8}, + {StdEncoding, 7, 12}, + } { + if got := tt.enc.EncodedLen(tt.n); got != tt.want { + t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want) + } + } +} + +func TestDecodedLen(t *testing.T) { + for _, tt := range []struct { + enc *Encoding + n int + want int + }{ + {RawStdEncoding, 0, 0}, + {RawStdEncoding, 2, 1}, + {RawStdEncoding, 3, 2}, + {RawStdEncoding, 4, 3}, + {RawStdEncoding, 10, 7}, + {StdEncoding, 0, 0}, + {StdEncoding, 4, 3}, + {StdEncoding, 8, 6}, + } { + if got := tt.enc.DecodedLen(tt.n); got != tt.want { + t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want) + } + } +} + func TestBig(t *testing.T) { n := 3*1000 + 1 raw := make([]byte, n) diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go index 1c2577b..46c6add 100644 --- a/libgo/go/encoding/binary/binary.go +++ b/libgo/go/encoding/binary/binary.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -48,18 +48,24 @@ var BigEndian bigEndian type littleEndian struct{} -func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 } +func (littleEndian) Uint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[0]) | uint16(b[1])<<8 +} func (littleEndian) PutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) } func (littleEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 } func (littleEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) @@ -67,11 +73,13 @@ func (littleEndian) PutUint32(b []byte, v uint32) { } func (littleEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 } func (littleEndian) PutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v) b[1] = byte(v >> 8) b[2] = byte(v >> 16) @@ -88,18 +96,24 @@ func (littleEndian) GoString() string { return "binary.LittleEndian" } type bigEndian struct{} -func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 } +func (bigEndian) Uint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[1]) | uint16(b[0])<<8 +} func (bigEndian) PutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 8) b[1] = byte(v) } func (bigEndian) Uint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 } func (bigEndian) PutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 24) b[1] = byte(v >> 16) b[2] = byte(v >> 8) @@ -107,11 +121,13 @@ func (bigEndian) PutUint32(b []byte, v uint32) { } func (bigEndian) Uint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 } func (bigEndian) PutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below b[0] = byte(v >> 56) b[1] = byte(v >> 48) b[2] = byte(v >> 40) @@ -253,7 +269,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error { case *uint8: b[0] = *v case uint8: - b[0] = byte(v) + b[0] = v case []uint8: bs = v case *int16: diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go index 7fd36fa..c0728e9 100644 --- a/libgo/go/encoding/binary/binary_test.go +++ b/libgo/go/encoding/binary/binary_test.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -266,7 +266,7 @@ func TestBlankFields(t *testing.T) { } // An attempt to read into a struct with an unexported field will -// panic. This is probably not the best choice, but at this point +// panic. This is probably not the best choice, but at this point // anything else would be an API change. type Unexported struct { @@ -339,6 +339,33 @@ func TestReadTruncated(t *testing.T) { } } +func testUint64SmallSliceLengthPanics() (panicked bool) { + defer func() { + panicked = recover() != nil + }() + b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} + LittleEndian.Uint64(b[:4]) + return false +} + +func testPutUint64SmallSliceLengthPanics() (panicked bool) { + defer func() { + panicked = recover() != nil + }() + b := [8]byte{} + LittleEndian.PutUint64(b[:4], 0x0102030405060708) + return false +} + +func TestEarlyBoundsChecks(t *testing.T) { + if testUint64SmallSliceLengthPanics() != true { + t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't") + } + if testPutUint64SmallSliceLengthPanics() != true { + t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't") + } +} + type byteSliceReader struct { remain []byte } @@ -373,8 +400,8 @@ func BenchmarkReadStruct(b *testing.B) { Read(bsr, BigEndian, &t) } b.StopTimer() - if !reflect.DeepEqual(s, t) { - b.Fatal("no match") + if b.N > 0 && !reflect.DeepEqual(s, t) { + b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", t, s) } } @@ -405,8 +432,8 @@ func BenchmarkReadInts(b *testing.B) { want.Array[i] = 0 } b.StopTimer() - if !reflect.DeepEqual(ls, want) { - panic("no match") + if b.N > 0 && !reflect.DeepEqual(ls, want) { + b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want) } } @@ -427,7 +454,7 @@ func BenchmarkWriteInts(b *testing.B) { Write(w, BigEndian, s.Uint64) } b.StopTimer() - if !bytes.Equal(buf.Bytes(), big[:30]) { + if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) { b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30]) } } diff --git a/libgo/go/encoding/binary/varint.go b/libgo/go/encoding/binary/varint.go index 3a2dfa3c..d7a75f9 100644 --- a/libgo/go/encoding/binary/varint.go +++ b/libgo/go/encoding/binary/varint.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go index a6bb780..a5e03a9 100644 --- a/libgo/go/encoding/csv/reader.go +++ b/libgo/go/encoding/csv/reader.go @@ -3,6 +3,8 @@ // license that can be found in the LICENSE file. // Package csv reads and writes comma-separated values (CSV) files. +// There are many kinds of CSV files; this package supports the format +// described in RFC 4180. // // A csv file contains zero or more records of one or more fields per record. // Each record is separated by the newline character. The final record may @@ -14,11 +16,11 @@ // // Carriage returns before newline characters are silently removed. // -// Blank lines are ignored. A line with only whitespace characters (excluding +// Blank lines are ignored. A line with only whitespace characters (excluding // the ending newline character) is not considered a blank line. // // Fields which start and stop with the quote character " are called -// quoted-fields. The beginning and ending quote are not part of the +// quoted-fields. The beginning and ending quote are not part of the // field. // // The source: @@ -84,32 +86,35 @@ var ( // The exported fields can be changed to customize the details before the // first call to Read or ReadAll. // -// Comma is the field delimiter. It defaults to ','. // -// Comment, if not 0, is the comment character. Lines beginning with the -// Comment character are ignored. -// -// If FieldsPerRecord is positive, Read requires each record to -// have the given number of fields. If FieldsPerRecord is 0, Read sets it to -// the number of fields in the first record, so that future records must -// have the same field count. If FieldsPerRecord is negative, no check is -// made and records may have a variable number of fields. -// -// If LazyQuotes is true, a quote may appear in an unquoted field and a -// non-doubled quote may appear in a quoted field. -// -// If TrimLeadingSpace is true, leading white space in a field is ignored. type Reader struct { - Comma rune // field delimiter (set to ',' by NewReader) - Comment rune // comment character for start of line - FieldsPerRecord int // number of expected fields per record - LazyQuotes bool // allow lazy quotes - TrailingComma bool // ignored; here for backwards compatibility - TrimLeadingSpace bool // trim leading space - line int - column int - r *bufio.Reader - field bytes.Buffer + // Comma is the field delimiter. + // It is set to comma (',') by NewReader. + Comma rune + // Comment, if not 0, is the comment character. Lines beginning with the + // Comment character without preceding whitespace are ignored. + // With leading whitespace the Comment character becomes part of the + // field, even if TrimLeadingSpace is true. + Comment rune + // FieldsPerRecord is the number of expected fields per record. + // If FieldsPerRecord is positive, Read requires each record to + // have the given number of fields. If FieldsPerRecord is 0, Read sets it to + // the number of fields in the first record, so that future records must + // have the same field count. If FieldsPerRecord is negative, no check is + // made and records may have a variable number of fields. + FieldsPerRecord int + // If LazyQuotes is true, a quote may appear in an unquoted field and a + // non-doubled quote may appear in a quoted field. + LazyQuotes bool + TrailingComma bool // ignored; here for backwards compatibility + // If TrimLeadingSpace is true, leading white space in a field is ignored. + // This is done even if the field delimiter, Comma, is white space. + TrimLeadingSpace bool + + line int + column int + r *bufio.Reader + field bytes.Buffer } // NewReader returns a new Reader that reads from r. @@ -129,7 +134,7 @@ func (r *Reader) error(err error) error { } } -// Read reads one record from r. The record is a slice of strings with each +// Read reads one record from r. The record is a slice of strings with each // string representing one field. func (r *Reader) Read() (record []string, err error) { for { @@ -177,7 +182,7 @@ func (r *Reader) ReadAll() (records [][]string, err error) { func (r *Reader) readRune() (rune, error) { r1, _, err := r.r.ReadRune() - // Handle \r\n here. We make the simplifying assumption that + // Handle \r\n here. We make the simplifying assumption that // anytime \r is followed by \n that it can be folded to \n. // We will not detect files which contain both \r\n and bare \n. if r1 == '\r' { @@ -208,13 +213,13 @@ func (r *Reader) skip(delim rune) error { // parseRecord reads and parses a single csv record from r. func (r *Reader) parseRecord() (fields []string, err error) { - // Each record starts on a new line. We increment our line + // Each record starts on a new line. We increment our line // number (lines start at 1, not 0) and set column to -1 // so as we increment in readRune it points to the character we read. r.line++ r.column = -1 - // Peek at the first rune. If it is an error we are done. + // Peek at the first rune. If it is an error we are done. // If we support comments and it is the comment character // then skip to the end of line. @@ -232,7 +237,7 @@ func (r *Reader) parseRecord() (fields []string, err error) { for { haveField, delim, err := r.parseField() if haveField { - // If FieldsPerRecord is greater then 0 we can assume the final + // If FieldsPerRecord is greater than 0 we can assume the final // length of fields to be equal to FieldsPerRecord. if r.FieldsPerRecord > 0 && fields == nil { fields = make([]string, 0, r.FieldsPerRecord) @@ -247,8 +252,8 @@ func (r *Reader) parseRecord() (fields []string, err error) { } } -// parseField parses the next field in the record. The read field is -// located in r.field. Delim is the first character not part of the field +// parseField parses the next field in the record. The read field is +// located in r.field. Delim is the first character not part of the field // (r.Comma or '\n'). func (r *Reader) parseField() (haveField bool, delim rune, err error) { r.field.Reset() diff --git a/libgo/go/encoding/csv/writer.go b/libgo/go/encoding/csv/writer.go index 353d91f..84b7aa1 100644 --- a/libgo/go/encoding/csv/writer.go +++ b/libgo/go/encoding/csv/writer.go @@ -15,7 +15,7 @@ import ( // A Writer writes records to a CSV encoded file. // // As returned by NewWriter, a Writer writes records terminated by a -// newline and uses ',' as the field delimiter. The exported fields can be +// newline and uses ',' as the field delimiter. The exported fields can be // changed to customize the details before the first call to Write or WriteAll. // // Comma is the field delimiter. @@ -37,27 +37,28 @@ func NewWriter(w io.Writer) *Writer { // Writer writes a single CSV record to w along with any necessary quoting. // A record is a slice of strings with each string being one field. -func (w *Writer) Write(record []string) (err error) { +func (w *Writer) Write(record []string) error { for n, field := range record { if n > 0 { - if _, err = w.w.WriteRune(w.Comma); err != nil { - return + if _, err := w.w.WriteRune(w.Comma); err != nil { + return err } } // If we don't have to have a quoted field then just // write out the field and continue to the next field. if !w.fieldNeedsQuotes(field) { - if _, err = w.w.WriteString(field); err != nil { - return + if _, err := w.w.WriteString(field); err != nil { + return err } continue } - if err = w.w.WriteByte('"'); err != nil { - return + if err := w.w.WriteByte('"'); err != nil { + return err } for _, r1 := range field { + var err error switch r1 { case '"': _, err = w.w.WriteString(`""`) @@ -75,20 +76,21 @@ func (w *Writer) Write(record []string) (err error) { _, err = w.w.WriteRune(r1) } if err != nil { - return + return err } } - if err = w.w.WriteByte('"'); err != nil { - return + if err := w.w.WriteByte('"'); err != nil { + return err } } + var err error if w.UseCRLF { _, err = w.w.WriteString("\r\n") } else { err = w.w.WriteByte('\n') } - return + return err } // Flush writes any buffered data to the underlying io.Writer. @@ -104,9 +106,9 @@ func (w *Writer) Error() error { } // WriteAll writes multiple CSV records to w using Write and then calls Flush. -func (w *Writer) WriteAll(records [][]string) (err error) { +func (w *Writer) WriteAll(records [][]string) error { for _, record := range records { - err = w.Write(record) + err := w.Write(record) if err != nil { return err } @@ -130,7 +132,7 @@ func (w *Writer) fieldNeedsQuotes(field string) bool { if field == "" { return false } - if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 { + if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") { return true } diff --git a/libgo/go/encoding/encoding.go b/libgo/go/encoding/encoding.go index 6d218071..cc5a536 100644 --- a/libgo/go/encoding/encoding.go +++ b/libgo/go/encoding/encoding.go @@ -1,4 +1,4 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go index 8efcdc7..d4002cb 100644 --- a/libgo/go/encoding/gob/codec_test.go +++ b/libgo/go/encoding/gob/codec_test.go @@ -970,7 +970,7 @@ func TestBadRecursiveType(t *testing.T) { err := NewEncoder(b).Encode(&rec) if err == nil { t.Error("expected error; got none") - } else if strings.Index(err.Error(), "recursive") < 0 { + } else if !strings.Contains(err.Error(), "recursive") { t.Error("expected recursive type error; got", err) } // Can't test decode easily because we can't encode one, so we can't pass one to a Decoder. @@ -1253,7 +1253,7 @@ func TestIgnoreInterface(t *testing.T) { if item2.I != item1.I { t.Error("normal int did not decode correctly") } - if item2.F != item2.F { + if item2.F != item1.F { t.Error("normal float did not decode correctly") } } @@ -1280,7 +1280,7 @@ func TestUnexportedFields(t *testing.T) { if err != nil { t.Fatal("decode error:", err) } - if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D { + if u0.A != u1.A || u0.B != u1.B || u0.D != u1.D { t.Errorf("u1->u0: expected %v; got %v", u0, u1) } if u1.c != 1234. { diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go index 536bbdb..d69d36f 100644 --- a/libgo/go/encoding/gob/debug.go +++ b/libgo/go/encoding/gob/debug.go @@ -7,7 +7,7 @@ package gob -// This file is not normally included in the gob package. Used only for debugging the package itself. +// This file is not normally included in the gob package. Used only for debugging the package itself. // Except for reading uints, it is an implementation of a reader that is independent of // the one implemented by Decoder. // To enable the Debug function, delete the +build ignore line above and do @@ -241,7 +241,7 @@ func (deb *debugger) delimitedMessage(indent tab) bool { // loadBlock preps us to read a message // of the length specified next in the input. It returns // the length of the block. The argument tells whether -// an EOF is acceptable now. If it is and one is found, +// an EOF is acceptable now. If it is and one is found, // the return value is negative. func (deb *debugger) loadBlock(eofOK bool) int { n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF @@ -339,7 +339,7 @@ func (deb *debugger) string() string { return string(b) } -// delta returns the field delta at the input point. The expect argument, +// delta returns the field delta at the input point. The expect argument, // if non-negative, identifies what the value should be. func (deb *debugger) delta(expect int) int { delta := int(deb.uint64()) diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go index 3b0dca8..9645dc5 100644 --- a/libgo/go/encoding/gob/decode.go +++ b/libgo/go/encoding/gob/decode.go @@ -216,10 +216,10 @@ func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) { } // Since the encoder writes no zeros, if we arrive at a decoder we have -// a value to extract and store. The field number has already been read +// a value to extract and store. The field number has already been read // (it's how we knew to call this decoder). // Each decoder is responsible for handling any indirections associated -// with the data structure. If any pointer so reached is nil, allocation must +// with the data structure. If any pointer so reached is nil, allocation must // be done. // decAlloc takes a value and returns a settable value that can @@ -308,9 +308,9 @@ func decUint64(i *decInstr, state *decoderState, value reflect.Value) { } // Floating-point numbers are transmitted as uint64s holding the bits -// of the underlying representation. They are sent byte-reversed, with +// of the underlying representation. They are sent byte-reversed, with // the exponent end coming out first, so integer floating point numbers -// (for example) transmit more compactly. This routine does the +// (for example) transmit more compactly. This routine does the // unswizzling. func float64FromBits(u uint64) float64 { var v uint64 @@ -332,7 +332,7 @@ func float32FromBits(u uint64, ovfl error) float64 { if av < 0 { av = -av } - // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. + // +Inf is OK in both 32- and 64-bit floats. Underflow is always OK. if math.MaxFloat32 < av && av <= math.MaxFloat64 { error_(ovfl) } @@ -421,7 +421,7 @@ func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) { // Execution engine // The encoder engine is an array of instructions indexed by field number of the incoming -// decoder. It is executed with random access according to field number. +// decoder. It is executed with random access according to field number. type decEngine struct { instr []decInstr numInstr int // the number of active instructions @@ -442,7 +442,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value refl } // decodeStruct decodes a top-level struct and stores it in value. -// Indir is for the value, not the type. At the time of the call it may +// Indir is for the value, not the type. At the time of the call it may // differ from ut.indir, which was computed when the engine was built. // This state cannot arise for decodeSingle, which is called directly // from the user's value, not from the innards of an engine. @@ -536,7 +536,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, } // decodeArray decodes an array and stores it in value. -// The length is an unsigned integer preceding the elements. Even though the length is redundant +// The length is an unsigned integer preceding the elements. Even though the length is redundant // (it's part of the type), it's a useful check and is included in the encoding. func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) { if n := state.decodeUint(); n != uint64(length) { @@ -645,10 +645,10 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu errorf("invalid type name length %d: exceeds input size", nr) } n := int(nr) - name := string(state.b.Bytes()[:n]) + name := state.b.Bytes()[:n] state.b.Drop(n) // Allocate the destination interface value. - if name == "" { + if len(name) == 0 { // Copy the nil interface value to the target. value.Set(reflect.Zero(value.Type())) return @@ -658,7 +658,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu } // The concrete type must be registered. registerLock.RLock() - typ, ok := nameToConcreteType[name] + typ, ok := nameToConcreteType[string(name)] registerLock.RUnlock() if !ok { errorf("name not registered for interface: %q", name) @@ -1075,7 +1075,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err return } -// compileDec compiles the decoder engine for a value. If the value is not a struct, +// compileDec compiles the decoder engine for a value. If the value is not a struct, // it calls out to compileSingle. func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) { defer catchError(&err) diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go index c453e9b..c182941 100644 --- a/libgo/go/encoding/gob/decoder.go +++ b/libgo/go/encoding/gob/decoder.go @@ -130,9 +130,9 @@ func (dec *Decoder) nextUint() uint64 { // decodeTypeSequence parses: // TypeSequence // (TypeDefinition DelimitedTypeDefinition*)? -// and returns the type id of the next value. It returns -1 at +// and returns the type id of the next value. It returns -1 at // EOF. Upon return, the remainder of dec.buf is the value to be -// decoded. If this is an interface value, it can be ignored by +// decoded. If this is an interface value, it can be ignored by // resetting that buffer. func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { for dec.err == nil { @@ -150,7 +150,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { // Type definition for (-id) follows. dec.recvType(-id) // When decoding an interface, after a type there may be a - // DelimitedValue still in the buffer. Skip its count. + // DelimitedValue still in the buffer. Skip its count. // (Alternatively, the buffer is empty and the byte count // will be absorbed by recvMessage.) if dec.buf.Len() > 0 { @@ -177,7 +177,7 @@ func (dec *Decoder) Decode(e interface{}) error { } value := reflect.ValueOf(e) // If e represents a value as opposed to a pointer, the answer won't - // get back to the caller. Make sure it's a pointer. + // get back to the caller. Make sure it's a pointer. if value.Type().Kind() != reflect.Ptr { dec.err = errors.New("gob: attempt to decode into a non-pointer") return dec.err @@ -187,7 +187,7 @@ func (dec *Decoder) Decode(e interface{}) error { // DecodeValue reads the next value from the input stream. // If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value. -// Otherwise, it stores the value into v. In that case, v must represent +// Otherwise, it stores the value into v. In that case, v must represent // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet()) // If the input is at EOF, DecodeValue returns io.EOF and // does not modify v. diff --git a/libgo/go/encoding/gob/doc.go b/libgo/go/encoding/gob/doc.go index cf878f4..1536574 100644 --- a/libgo/go/encoding/gob/doc.go +++ b/libgo/go/encoding/gob/doc.go @@ -17,7 +17,8 @@ Basics A stream of gobs is self-describing. Each data item in the stream is preceded by a specification of its type, expressed in terms of a small set of predefined types. Pointers are not transmitted, but the things they point to are -transmitted; that is, the values are flattened. Recursive types work fine, but +transmitted; that is, the values are flattened. Nil pointers are not permitted, +as they have no value. Recursive types work fine, but recursive values (data with cycles) are problematic. This may change. To use gobs, create an Encoder and present it with a series of data items as @@ -254,6 +255,12 @@ In summary, a gob stream looks like where * signifies zero or more repetitions and the type id of a value must be predefined or be defined before the value in the stream. +Compatibility: Any future changes to the package will endeavor to maintain +compatibility with streams encoded using previous versions. That is, any released +version of this package should be able to decode data written with any previously +released version, subject to issues such as security fixes. See the Go compatibility +document for background: https://golang.org/doc/go1compat + See "Gobs of data" for a design discussion of the gob wire format: https://blog.golang.org/gobs-of-data */ diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go index 96052ef..50cd6ad 100644 --- a/libgo/go/encoding/gob/encode.go +++ b/libgo/go/encoding/gob/encode.go @@ -96,7 +96,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) { enc.freeList = e } -// Unsigned integers have a two-state encoding. If the number is less +// Unsigned integers have a two-state encoding. If the number is less // than 128 (0 through 0x7F), its value is written directly. // Otherwise the value is written in big-endian byte order preceded // by the byte length, negated. @@ -127,7 +127,7 @@ func (state *encoderState) encodeInt(i int64) { } else { x = uint64(i << 1) } - state.encodeUint(uint64(x)) + state.encodeUint(x) } // encOp is the signature of an encoding operator for a given type. @@ -152,8 +152,8 @@ func (state *encoderState) update(instr *encInstr) { // Each encoder for a composite is responsible for handling any // indirections associated with the elements of the data structure. -// If any pointer so reached is nil, no bytes are written. If the -// data item is zero, no bytes are written. Single values - ints, +// If any pointer so reached is nil, no bytes are written. If the +// data item is zero, no bytes are written. Single values - ints, // strings etc. - are indirected before calling their encoders. // Otherwise, the output (for a scalar) is the field number, as an // encoded integer, followed by the field data in its appropriate @@ -203,9 +203,9 @@ func encUint(i *encInstr, state *encoderState, v reflect.Value) { // floatBits returns a uint64 holding the bits of a floating-point number. // Floating-point numbers are transmitted as uint64s holding the bits -// of the underlying representation. They are sent byte-reversed, with +// of the underlying representation. They are sent byte-reversed, with // the exponent end coming out first, so integer floating point numbers -// (for example) transmit more compactly. This routine does the +// (for example) transmit more compactly. This routine does the // swizzling. func floatBits(f float64) uint64 { u := math.Float64bits(f) @@ -272,7 +272,7 @@ func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) { // Execution engine // encEngine an array of instructions indexed by field number of the encoding -// data, typically a struct. It is executed top to bottom, walking the struct. +// data, typically a struct. It is executed top to bottom, walking the struct. type encEngine struct { instr []encInstr } @@ -297,7 +297,7 @@ func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect. defer enc.freeEncoderState(state) state.fieldnum = singletonField // There is no surrounding struct to frame the transmission, so we must - // generate data even if the item is zero. To do this, set sendZero. + // generate data even if the item is zero. To do this, set sendZero. state.sendZero = true instr := &engine.instr[singletonField] if instr.indir > 0 { @@ -386,7 +386,7 @@ func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encO // encodeInterface encodes the interface value iv. // To send an interface, we send a string identifying the concrete type, followed // by the type identifier (which might require defining that type right now), followed -// by the concrete value. A nil value gets sent as the empty string for the name, +// by the concrete value. A nil value gets sent as the empty string for the name, // followed by no value. func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) { // Gobs can encode nil interface values but not typed interface @@ -417,7 +417,7 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) { enc.sendTypeDescriptor(enc.writer(), state, ut) // Send the type id. enc.sendTypeId(state, ut) - // Encode the value into a new buffer. Any nested type definitions + // Encode the value into a new buffer. Any nested type definitions // should be written to b, before the encoded value. enc.pushWriter(b) data := encBufferPool.Get().(*encBuffer) diff --git a/libgo/go/encoding/gob/encoder.go b/libgo/go/encoding/gob/encoder.go index 62d0f42..d6c8fdd 100644 --- a/libgo/go/encoding/gob/encoder.go +++ b/libgo/go/encoding/gob/encoder.go @@ -170,6 +170,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ // Encode transmits the data item represented by the empty interface value, // guaranteeing that all necessary type information has been transmitted first. +// Passing a nil pointer to Encoder will panic, as they cannot be transmitted by gob. func (enc *Encoder) Encode(e interface{}) error { return enc.EncodeValue(reflect.ValueOf(e)) } @@ -191,7 +192,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use return } // If the type info has still not been transmitted, it means we have - // a singleton basic type (int, []byte etc.) at top level. We don't + // a singleton basic type (int, []byte etc.) at top level. We don't // need to send the type info but we do need to update enc.sent. if !sent { info, err := getTypeInfo(ut) @@ -212,9 +213,8 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) { // EncodeValue transmits the data item represented by the reflection value, // guaranteeing that all necessary type information has been transmitted first. +// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob. func (enc *Encoder) EncodeValue(value reflect.Value) error { - // Gobs contain values. They cannot represent nil pointers, which - // have no value to encode. if value.Kind() == reflect.Ptr && value.IsNil() { panic("gob: cannot encode nil pointer of type " + value.Type().String()) } diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go index 570d796..22090a1 100644 --- a/libgo/go/encoding/gob/encoder_test.go +++ b/libgo/go/encoding/gob/encoder_test.go @@ -8,6 +8,7 @@ import ( "bytes" "encoding/hex" "fmt" + "io/ioutil" "reflect" "strings" "testing" @@ -280,7 +281,7 @@ func TestValueError(t *testing.T) { } t4p := &Type4{3} var t4 Type4 // note: not a pointer. - if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 { + if err := encAndDec(t4p, t4); err == nil || !strings.Contains(err.Error(), "pointer") { t.Error("expected error about pointer; got", err) } } @@ -388,7 +389,7 @@ func TestSingletons(t *testing.T) { t.Errorf("expected error decoding %v: %s", test.in, test.err) continue case err != nil && test.err != "": - if strings.Index(err.Error(), test.err) < 0 { + if !strings.Contains(err.Error(), test.err) { t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err) } continue @@ -414,7 +415,7 @@ func TestStructNonStruct(t *testing.T) { var ns NonStruct if err := encAndDec(s, &ns); err == nil { t.Error("should get error for struct/non-struct") - } else if strings.Index(err.Error(), "type") < 0 { + } else if !strings.Contains(err.Error(), "type") { t.Error("for struct/non-struct expected type error; got", err) } // Now try the other way @@ -424,7 +425,7 @@ func TestStructNonStruct(t *testing.T) { } if err := encAndDec(ns, &s); err == nil { t.Error("should get error for non-struct/struct") - } else if strings.Index(err.Error(), "type") < 0 { + } else if !strings.Contains(err.Error(), "type") { t.Error("for non-struct/struct expected type error; got", err) } } @@ -439,8 +440,8 @@ func (this *interfaceIndirectTestT) F() bool { return true } -// A version of a bug reported on golang-nuts. Also tests top-level -// slice of interfaces. The issue was registering *T caused T to be +// A version of a bug reported on golang-nuts. Also tests top-level +// slice of interfaces. The issue was registering *T caused T to be // stored as the concrete type. func TestInterfaceIndirect(t *testing.T) { Register(&interfaceIndirectTestT{}) @@ -463,7 +464,7 @@ func TestInterfaceIndirect(t *testing.T) { // Also, when the ignored object contains an interface value, it may define // types. Make sure that skipping the value still defines the types by using -// the encoder/decoder pair to send a value afterwards. If an interface +// the encoder/decoder pair to send a value afterwards. If an interface // is sent, its type in the test is always NewType0, so this checks that the // encoder and decoder don't skew with respect to type definitions. @@ -603,10 +604,6 @@ type Bug1Elem struct { type Bug1StructMap map[string]Bug1Elem -func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) error { - return nil -} - func TestMapBug1(t *testing.T) { in := make(Bug1StructMap) in["val1"] = Bug1Elem{"elem1", 1} @@ -835,30 +832,81 @@ func TestPtrToMapOfMap(t *testing.T) { // A top-level nil pointer generates a panic with a helpful string-valued message. func TestTopLevelNilPointer(t *testing.T) { - errMsg := topLevelNilPanic(t) - if errMsg == "" { + var ip *int + encodeErr, panicErr := encodeAndRecover(ip) + if encodeErr != nil { + t.Fatal("error in encode:", encodeErr) + } + if panicErr == nil { t.Fatal("top-level nil pointer did not panic") } + errMsg := panicErr.Error() if !strings.Contains(errMsg, "nil pointer") { t.Fatal("expected nil pointer error, got:", errMsg) } } -func topLevelNilPanic(t *testing.T) (panicErr string) { +func encodeAndRecover(value interface{}) (encodeErr, panicErr error) { defer func() { e := recover() - if err, ok := e.(string); ok { - panicErr = err + if e != nil { + switch err := e.(type) { + case error: + panicErr = err + default: + panicErr = fmt.Errorf("%v", err) + } } }() - var ip *int - buf := new(bytes.Buffer) - if err := NewEncoder(buf).Encode(ip); err != nil { - t.Fatal("error in encode:", err) - } + + encodeErr = NewEncoder(ioutil.Discard).Encode(value) return } +func TestNilPointerPanics(t *testing.T) { + var ( + nilStringPtr *string + intMap = make(map[int]int) + intMapPtr = &intMap + nilIntMapPtr *map[int]int + zero int + nilBoolChannel chan bool + nilBoolChannelPtr *chan bool + nilStringSlice []string + stringSlice = make([]string, 1) + nilStringSlicePtr *[]string + ) + + testCases := []struct { + value interface{} + mustPanic bool + }{ + {nilStringPtr, true}, + {intMap, false}, + {intMapPtr, false}, + {nilIntMapPtr, true}, + {zero, false}, + {nilStringSlice, false}, + {stringSlice, false}, + {nilStringSlicePtr, true}, + {nilBoolChannel, false}, + {nilBoolChannelPtr, true}, + } + + for _, tt := range testCases { + _, panicErr := encodeAndRecover(tt.value) + if tt.mustPanic { + if panicErr == nil { + t.Errorf("expected panic with input %#v, did not panic", tt.value) + } + continue + } + if panicErr != nil { + t.Fatalf("expected no panic with input %#v, got panic=%v", tt.value, panicErr) + } + } +} + func TestNilPointerInsideInterface(t *testing.T) { var ip *int si := struct { @@ -913,7 +961,7 @@ func TestMutipleEncodingsOfBadType(t *testing.T) { // There was an error check comparing the length of the input with the // length of the slice being decoded. It was wrong because the next // thing in the input might be a type definition, which would lead to -// an incorrect length check. This test reproduces the corner case. +// an incorrect length check. This test reproduces the corner case. type Z struct { } diff --git a/libgo/go/encoding/gob/error.go b/libgo/go/encoding/gob/error.go index 92cc0c6..8b5265c 100644 --- a/libgo/go/encoding/gob/error.go +++ b/libgo/go/encoding/gob/error.go @@ -9,7 +9,7 @@ import "fmt" // Errors in decoding and encoding are handled using panic and recover. // Panics caused by user error (that is, everything except run-time panics // such as "index out of bounds" errors) do not leave the file that caused -// them, but are instead turned into plain error returns. Encoding and +// them, but are instead turned into plain error returns. Encoding and // decoding functions and methods that do not return an error either use // panic to report an error or are guaranteed error-free. @@ -30,7 +30,7 @@ func error_(err error) { } // catchError is meant to be used as a deferred function to turn a panic(gobError) into a -// plain error. It overwrites the error return of the function that deferred its call. +// plain error. It overwrites the error return of the function that deferred its call. func catchError(err *error) { if e := recover(); e != nil { ge, ok := e.(gobError) diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go index eb76b48..ecc91ee 100644 --- a/libgo/go/encoding/gob/gobencdec_test.go +++ b/libgo/go/encoding/gob/gobencdec_test.go @@ -376,7 +376,7 @@ func TestGobEncoderIndirectArrayField(t *testing.T) { } // As long as the fields have the same name and implement the -// interface, we can cross-connect them. Not sure it's useful +// interface, we can cross-connect them. Not sure it's useful // and may even be bad but it works and it's hard to prevent // without exposing the contents of the object, which would // defeat the purpose. @@ -434,7 +434,7 @@ func TestGobEncoderValueEncoder(t *testing.T) { } // Test that we can use a value then a pointer type of a GobEncoder -// in the same encoded value. Bug 4647. +// in the same encoded value. Bug 4647. func TestGobEncoderValueThenPointer(t *testing.T) { v := ValueGobber("forty-two") w := ValueGobber("six-by-nine") @@ -548,7 +548,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) { if err == nil { t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)") } - if strings.Index(err.Error(), "type") < 0 { + if !strings.Contains(err.Error(), "type") { t.Fatal("expected type error; got", err) } // Non-encoder to GobDecoder: error @@ -562,7 +562,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) { if err == nil { t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)") } - if strings.Index(err.Error(), "type") < 0 { + if !strings.Contains(err.Error(), "type") { t.Fatal("expected type error; got", err) } } diff --git a/libgo/go/encoding/gob/type.go b/libgo/go/encoding/gob/type.go index cf5cec0..c27f7e9 100644 --- a/libgo/go/encoding/gob/type.go +++ b/libgo/go/encoding/gob/type.go @@ -17,7 +17,7 @@ import ( ) // userTypeInfo stores the information associated with a type the user has handed -// to the package. It's computed once and stored in a map keyed by reflection +// to the package. It's computed once and stored in a map keyed by reflection // type. type userTypeInfo struct { user reflect.Type // the type the user handed us @@ -44,7 +44,7 @@ var ( ) // validType returns, and saves, the information associated with user-provided type rt. -// If the user type is not valid, err will be non-nil. To be used when the error handler +// If the user type is not valid, err will be non-nil. To be used when the error handler // is not set up. func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) { userTypeLock.RLock() @@ -64,7 +64,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) { ut.base = rt ut.user = rt // A type that is just a cycle of pointers (such as type T *T) cannot - // be represented in gobs, which need some concrete data. We use a + // be represented in gobs, which need some concrete data. We use a // cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6, // pp 539-540. As we step through indirections, run another type at // half speed. If they meet up, there's a cycle. @@ -493,7 +493,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err // For arrays, maps, and slices, we set the type id after the elements // are constructed. This is to retain the order of type id allocation after // a fix made to handle recursive types, which changed the order in - // which types are built. Delaying the setting in this way preserves + // which types are built. Delaying the setting in this way preserves // type ids while allowing recursive types to be described. Structs, // done below, were already handling recursion correctly so they // assign the top-level id before those of the field. @@ -597,7 +597,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, error) { // getType returns the Gob type describing the given reflect.Type. // Should be called only when handling GobEncoders/Decoders, -// which may be pointers. All other types are handled through the +// which may be pointers. All other types are handled through the // base type, never a pointer. // typeLock must be held. func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) { @@ -642,7 +642,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId { // For bootstrapping purposes, we assume that the recipient knows how // to decode a wireType; it is exactly the wireType struct here, interpreted // using the gob rules for sending a structure, except that we assume the -// ids for wireType and structType etc. are known. The relevant pieces +// ids for wireType and structType etc. are known. The relevant pieces // are built in encode.go's init() function. // To maintain binary compatibility, if you extend this type, always put // the new fields last. @@ -789,7 +789,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo { // // Note: Since gobs can be stored permanently, it is good design // to guarantee the encoding used by a GobEncoder is stable as the -// software evolves. For instance, it might make sense for GobEncode +// software evolves. For instance, it might make sense for GobEncode // to include a version number in the encoding. type GobEncoder interface { // GobEncode returns a byte slice representing the encoding of the @@ -838,8 +838,8 @@ func RegisterName(name string, value interface{}) { } // Register records a type, identified by a value for that type, under its -// internal type name. That name will identify the concrete type of a value -// sent or received as an interface variable. Only types that will be +// internal type name. That name will identify the concrete type of a value +// sent or received as an interface variable. Only types that will be // transferred as implementations of interface values need to be registered. // Expecting to be used only during initialization, it panics if the mapping // between types and names is not a bijection. diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go index d1fc702..73a2503 100644 --- a/libgo/go/encoding/hex/hex.go +++ b/libgo/go/encoding/hex/hex.go @@ -18,7 +18,7 @@ const hextable = "0123456789abcdef" func EncodedLen(n int) int { return n * 2 } // Encode encodes src into EncodedLen(len(src)) -// bytes of dst. As a convenience, it returns the number +// bytes of dst. As a convenience, it returns the number // of bytes written to dst, but this value is always EncodedLen(len(src)). // Encode implements hexadecimal encoding. func Encode(dst, src []byte) int { @@ -105,7 +105,7 @@ func Dump(data []byte) string { dumper := Dumper(&buf) dumper.Write(data) dumper.Close() - return string(buf.Bytes()) + return buf.String() } // Dumper returns a WriteCloser that writes a hex dump of all written data to diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go index ed89d11..cd7380b 100644 --- a/libgo/go/encoding/json/bench_test.go +++ b/libgo/go/encoding/json/bench_test.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -158,7 +158,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) { for i := 0; i < b.N; i++ { var r codeResponse if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatal("Unmmarshal:", err) + b.Fatal("Unmarshal:", err) } } b.SetBytes(int64(len(codeJSON))) @@ -173,7 +173,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) { var r codeResponse for i := 0; i < b.N; i++ { if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatal("Unmmarshal:", err) + b.Fatal("Unmarshal:", err) } } } diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 539d952..2eda875 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -29,9 +29,9 @@ import ( // with the following additional rules: // // To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal // allocates a new value for it to point to. // // To unmarshal JSON into a struct, Unmarshal matches incoming object @@ -61,10 +61,11 @@ import ( // If the JSON array is smaller than the Go array, // the additional Go array elements are set to zero values. // -// To unmarshal a JSON object into a string-keyed map, Unmarshal first -// establishes a map to use, If the map is nil, Unmarshal allocates a new map. -// Otherwise Unmarshal reuses the existing map, keeping existing entries. -// Unmarshal then stores key-value pairs from the JSON object into the map. +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores key- +// value pairs from the JSON object into the map. The map's key type must +// either be a string, an integer, or implement encoding.TextUnmarshaler. // // If a JSON value is not appropriate for a given target type, // or if a JSON number overflows the target type, Unmarshal @@ -96,7 +97,7 @@ func Unmarshal(data []byte, v interface{}) error { return d.unmarshal(v) } -// Unmarshaler is the interface implemented by objects +// Unmarshaler is the interface implemented by types // that can unmarshal a JSON description of themselves. // The input can be assumed to be a valid encoding of // a JSON value. UnmarshalJSON must copy the JSON data @@ -534,7 +535,7 @@ func (d *decodeState) array(v reflect.Value) { if i < v.Len() { if v.Kind() == reflect.Array { - // Array. Zero the rest. + // Array. Zero the rest. z := reflect.Zero(v.Type().Elem()) for ; i < v.Len(); i++ { v.Index(i).Set(z) @@ -549,6 +550,7 @@ func (d *decodeState) array(v reflect.Value) { } var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() // object consumes an object from d.data[d.off-1:], decoding into the value v. // the first byte ('{') of the object has been read already. @@ -577,16 +579,26 @@ func (d *decodeState) object(v reflect.Value) { return } - // Check type of target: struct or map[string]T + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler switch v.Kind() { case reflect.Map: - // map must have string kind + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. t := v.Type() - if t.Key().Kind() != reflect.String { - d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) - d.off-- - d.next() // skip over { } in input - return + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) + d.off-- + d.next() // skip over { } in input + return + } } if v.IsNil() { v.Set(reflect.MakeMap(t)) @@ -687,7 +699,37 @@ func (d *decodeState) object(v reflect.Value) { // Write value back to map; // if using struct, subv points into struct already. if v.Kind() == reflect.Map { - kv := reflect.ValueOf(key).Convert(v.Type().Key()) + kt := v.Type().Key() + var kv reflect.Value + switch { + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + case reflect.PtrTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(v.Type().Key()) + d.literalStore(item, kv, true) + kv = kv.Elem() + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)}) + return + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)}) + return + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } v.SetMapIndex(kv, subv) } @@ -902,7 +944,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } // The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, +// in an empty interface. They are not strictly necessary, // but they avoid the weight of reflection in this common case. // valueInterface is like value but returns interface{} diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index 9546ae4..255ff5c 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -7,10 +7,13 @@ package json import ( "bytes" "encoding" + "errors" "fmt" "image" + "math" "net" "reflect" + "strconv" "strings" "testing" "time" @@ -52,6 +55,8 @@ type tx struct { x int } +type u8 uint8 + // A type that can unmarshal itself. type unmarshaler struct { @@ -68,16 +73,20 @@ type ustruct struct { } type unmarshalerText struct { - T bool + A, B string } // needed for re-marshaling tests -func (u *unmarshalerText) MarshalText() ([]byte, error) { - return []byte(""), nil +func (u unmarshalerText) MarshalText() ([]byte, error) { + return []byte(u.A + ":" + u.B), nil } func (u *unmarshalerText) UnmarshalText(b []byte) error { - *u = unmarshalerText{true} // All we need to see that UnmarshalText is called. + pos := bytes.Index(b, []byte(":")) + if pos == -1 { + return errors.New("missing separator") + } + u.A, u.B = string(b[:pos]), string(b[pos+1:]) return nil } @@ -87,6 +96,29 @@ type ustructText struct { M unmarshalerText } +// u8marshal is an integer type that can marshal/unmarshal itself. +type u8marshal uint8 + +func (u8 u8marshal) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("u%d", u8)), nil +} + +var errMissingU8Prefix = errors.New("missing 'u' prefix") + +func (u8 *u8marshal) UnmarshalText(b []byte) error { + if !bytes.HasPrefix(b, []byte{'u'}) { + return errMissingU8Prefix + } + n, err := strconv.Atoi(string(b[1:])) + if err != nil { + return err + } + *u8 = u8marshal(n) + return nil +} + +var _ encoding.TextUnmarshaler = (*u8marshal)(nil) + var ( um0, um1 unmarshaler // target2 of unmarshaling ump = &um1 @@ -95,12 +127,16 @@ var ( umslicep = new([]unmarshaler) umstruct = ustruct{unmarshaler{true}} - um0T, um1T unmarshalerText // target2 of unmarshaling - umpT = &um1T - umtrueT = unmarshalerText{true} - umsliceT = []unmarshalerText{{true}} - umslicepT = new([]unmarshalerText) - umstructT = ustructText{unmarshalerText{true}} + um0T, um1T unmarshalerText // target2 of unmarshaling + umpType = &um1T + umtrueXY = unmarshalerText{"x", "y"} + umsliceXY = []unmarshalerText{{"x", "y"}} + umslicepType = new([]unmarshalerText) + umstructType = new(ustructText) + umstructXY = ustructText{unmarshalerText{"x", "y"}} + + ummapType = map[unmarshalerText]bool{} + ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true} ) // Test data structures for anonymous fields. @@ -202,14 +238,6 @@ type S13 struct { S8 } -type unmarshalTest struct { - in string - ptr interface{} - out interface{} - err error - useNumber bool -} - type Ambig struct { // Given "hello", the first match should win. First int `json:"HELLO"` @@ -225,6 +253,127 @@ type XYZ struct { func sliceAddr(x []int) *[]int { return &x } func mapAddr(x map[string]int) *map[string]int { return &x } +type byteWithMarshalJSON byte + +func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil +} + +func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { + if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[2:4]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = byteWithMarshalJSON(i) + return nil +} + +type byteWithPtrMarshalJSON byte + +func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { + return byteWithMarshalJSON(*b).MarshalJSON() +} + +func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { + return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) +} + +type byteWithMarshalText byte + +func (b byteWithMarshalText) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil +} + +func (b *byteWithMarshalText) UnmarshalText(data []byte) error { + if len(data) != 3 || data[0] != 'Z' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[1:3]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = byteWithMarshalText(i) + return nil +} + +type byteWithPtrMarshalText byte + +func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { + return byteWithMarshalText(*b).MarshalText() +} + +func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { + return (*byteWithMarshalText)(b).UnmarshalText(data) +} + +type intWithMarshalJSON int + +func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil +} + +func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { + if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[2:4]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = intWithMarshalJSON(i) + return nil +} + +type intWithPtrMarshalJSON int + +func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { + return intWithMarshalJSON(*b).MarshalJSON() +} + +func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { + return (*intWithMarshalJSON)(b).UnmarshalJSON(data) +} + +type intWithMarshalText int + +func (b intWithMarshalText) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil +} + +func (b *intWithMarshalText) UnmarshalText(data []byte) error { + if len(data) != 3 || data[0] != 'Z' { + return fmt.Errorf("bad quoted string") + } + i, err := strconv.ParseInt(string(data[1:3]), 16, 8) + if err != nil { + return fmt.Errorf("bad hex") + } + *b = intWithMarshalText(i) + return nil +} + +type intWithPtrMarshalText int + +func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { + return intWithMarshalText(*b).MarshalText() +} + +func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { + return (*intWithMarshalText)(b).UnmarshalText(data) +} + +type unmarshalTest struct { + in string + ptr interface{} + out interface{} + err error + useNumber bool + golden bool +} + var unmarshalTests = []unmarshalTest{ // basic types {in: `true`, ptr: new(bool), out: true}, @@ -302,14 +451,81 @@ var unmarshalTests = []unmarshalTest{ {in: `{"T":false}`, ptr: &ump, out: &umtrue}, {in: `[{"T":false}]`, ptr: &umslice, out: umslice}, {in: `[{"T":false}]`, ptr: &umslicep, out: &umslice}, - {in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct}, + {in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct}, // UnmarshalText interface test - {in: `"X"`, ptr: &um0T, out: umtrueT}, // use "false" so test will fail if custom unmarshaler is not called - {in: `"X"`, ptr: &umpT, out: &umtrueT}, - {in: `["X"]`, ptr: &umsliceT, out: umsliceT}, - {in: `["X"]`, ptr: &umslicepT, out: &umsliceT}, - {in: `{"M":"X"}`, ptr: &umstructT, out: umstructT}, + {in: `"x:y"`, ptr: &um0T, out: umtrueXY}, + {in: `"x:y"`, ptr: &umpType, out: &umtrueXY}, + {in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY}, + {in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY}, + {in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY}, + + // integer-keyed map test + { + in: `{"-1":"a","0":"b","1":"c"}`, + ptr: new(map[int]string), + out: map[int]string{-1: "a", 0: "b", 1: "c"}, + }, + { + in: `{"0":"a","10":"c","9":"b"}`, + ptr: new(map[u8]string), + out: map[u8]string{0: "a", 9: "b", 10: "c"}, + }, + { + in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, + ptr: new(map[int64]string), + out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, + }, + { + in: `{"18446744073709551615":"max"}`, + ptr: new(map[uint64]string), + out: map[uint64]string{math.MaxUint64: "max"}, + }, + { + in: `{"0":false,"10":true}`, + ptr: new(map[uintptr]bool), + out: map[uintptr]bool{0: false, 10: true}, + }, + + // Check that MarshalText and UnmarshalText take precedence + // over default integer handling in map keys. + { + in: `{"u2":4}`, + ptr: new(map[u8marshal]int), + out: map[u8marshal]int{2: 4}, + }, + { + in: `{"2":4}`, + ptr: new(map[u8marshal]int), + err: errMissingU8Prefix, + }, + + // integer-keyed map errors + { + in: `{"abc":"abc"}`, + ptr: new(map[int]string), + err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2}, + }, + { + in: `{"256":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2}, + }, + { + in: `{"128":"abc"}`, + ptr: new(map[int8]string), + err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2}, + }, + { + in: `{"-1":"abc"}`, + ptr: new(map[uint8]string), + err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2}, + }, + + // Map keys can be encoding.TextUnmarshalers. + {in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY}, + // If multiple values for the same key exists, only the most recent value is used. + {in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY}, // Overwriting of data. // This is different from package xml, but it's what we've always done. @@ -426,11 +642,101 @@ var unmarshalTests = []unmarshalTest{ out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", }, - // issue 8305 + // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. { in: `{"2009-11-10T23:00:00Z": "hello world"}`, ptr: &map[time.Time]string{}, - err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1}, + out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, + }, + + // issue 8305 + { + in: `{"2009-11-10T23:00:00Z": "hello world"}`, + ptr: &map[Point]string{}, + err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1}, + }, + { + in: `{"asdf": "hello world"}`, + ptr: &map[unmarshaler]string{}, + err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1}, + }, + + // related to issue 13783. + // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, + // similar to marshaling a slice of typed int. + // These tests check that, assuming the byte type also has valid decoding methods, + // either the old base64 string encoding or the new per-element encoding can be + // successfully unmarshaled. The custom unmarshalers were accessible in earlier + // versions of Go, even though the custom marshaler was not. + { + in: `"AQID"`, + ptr: new([]byteWithMarshalJSON), + out: []byteWithMarshalJSON{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithMarshalJSON), + out: []byteWithMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithMarshalText), + out: []byteWithMarshalText{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithMarshalText), + out: []byteWithMarshalText{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithPtrMarshalJSON), + out: []byteWithPtrMarshalJSON{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithPtrMarshalJSON), + out: []byteWithPtrMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `"AQID"`, + ptr: new([]byteWithPtrMarshalText), + out: []byteWithPtrMarshalText{1, 2, 3}, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]byteWithPtrMarshalText), + out: []byteWithPtrMarshalText{1, 2, 3}, + golden: true, + }, + + // ints work with the marshaler but not the base64 []byte case + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithMarshalJSON), + out: []intWithMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithMarshalText), + out: []intWithMarshalText{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithPtrMarshalJSON), + out: []intWithPtrMarshalJSON{1, 2, 3}, + golden: true, + }, + { + in: `["Z01","Z02","Z03"]`, + ptr: new([]intWithPtrMarshalText), + out: []intWithPtrMarshalText{1, 2, 3}, + golden: true, }, } @@ -565,13 +871,16 @@ func TestUnmarshal(t *testing.T) { continue } - // Check round trip. + // Check round trip also decodes correctly. if tt.err == nil { enc, err := Marshal(v.Interface()) if err != nil { t.Errorf("#%d: error re-marshaling: %v", i, err) continue } + if tt.golden && !bytes.Equal(enc, in) { + t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in) + } vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) dec = NewDecoder(bytes.NewReader(enc)) if tt.useNumber { @@ -1270,7 +1579,7 @@ func TestSliceOfCustomByte(t *testing.T) { t.Fatal(err) } if !reflect.DeepEqual(a, b) { - t.Fatal("expected %v == %v", a, b) + t.Fatalf("expected %v == %v", a, b) } } diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 69ac7e0..6bb6de8 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -1,9 +1,9 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package json implements encoding and decoding of JSON objects as defined in -// RFC 4627. The mapping between JSON objects and Go values is described +// Package json implements encoding and decoding of JSON as defined in +// RFC 4627. The mapping between JSON and Go values is described // in the documentation for the Marshal and Unmarshal functions. // // See "JSON and Go" for an introduction to this package: @@ -22,6 +22,7 @@ import ( "strconv" "strings" "sync" + "sync/atomic" "unicode" "unicode/utf8" ) @@ -49,10 +50,11 @@ import ( // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" // to keep some browsers from misinterpreting JSON output as HTML. // Ampersand "&" is also escaped to "\u0026" for the same reason. +// This escaping can be disabled using an Encoder with DisableHTMLEscaping. // // Array and slice values encode as JSON arrays, except that // []byte encodes as a base64-encoded string, and a nil slice -// encodes as the null JSON object. +// encodes as the null JSON value. // // Struct values encode as JSON objects. Each exported struct field // becomes a member of the object unless @@ -89,8 +91,8 @@ import ( // Int64String int64 `json:",string"` // // The key name will be used if it's a non-empty string consisting of -// only Unicode letters, digits, dollar signs, percent signs, hyphens, -// underscores and slashes. +// only Unicode letters, digits, and ASCII punctuation except quotation +// marks, backslash, and comma. // // Anonymous struct fields are usually marshaled as if their inner exported fields // were fields in the outer struct, subject to the usual Go visibility rules amended @@ -116,27 +118,31 @@ import ( // an anonymous struct field in both current and earlier versions, give the field // a JSON tag of "-". // -// Map values encode as JSON objects. -// The map's key type must be string; the map keys are used as JSON object -// keys, subject to the UTF-8 coercion described for string values above. +// Map values encode as JSON objects. The map's key type must either be a +// string, an integer type, or implement encoding.TextMarshaler. The map keys +// are sorted and used as JSON object keys by applying the following rules, +// subject to the UTF-8 coercion described for string values above: +// - string keys are used directly +// - encoding.TextMarshalers are marshaled +// - integer keys are converted to strings // // Pointer values encode as the value pointed to. -// A nil pointer encodes as the null JSON object. +// A nil pointer encodes as the null JSON value. // // Interface values encode as the value contained in the interface. -// A nil interface value encodes as the null JSON object. +// A nil interface value encodes as the null JSON value. // // Channel, complex, and function values cannot be encoded in JSON. // Attempting to encode such a value causes Marshal to return // an UnsupportedTypeError. // // JSON cannot represent cyclic data structures and Marshal does not -// handle them. Passing cyclic structures to Marshal will result in +// handle them. Passing cyclic structures to Marshal will result in // an infinite recursion. // func Marshal(v interface{}) ([]byte, error) { e := &encodeState{} - err := e.marshal(v) + err := e.marshal(v, encOpts{escapeHTML: true}) if err != nil { return nil, err } @@ -192,7 +198,7 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) { } } -// Marshaler is the interface implemented by objects that +// Marshaler is the interface implemented by types that // can marshal themselves into valid JSON. type Marshaler interface { MarshalJSON() ([]byte, error) @@ -259,7 +265,7 @@ func newEncodeState() *encodeState { return new(encodeState) } -func (e *encodeState) marshal(v interface{}) (err error) { +func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) { defer func() { if r := recover(); r != nil { if _, ok := r.(runtime.Error); ok { @@ -271,7 +277,7 @@ func (e *encodeState) marshal(v interface{}) (err error) { err = r.(error) } }() - e.reflectValue(reflect.ValueOf(v)) + e.reflectValue(reflect.ValueOf(v), opts) return nil } @@ -297,11 +303,18 @@ func isEmptyValue(v reflect.Value) bool { return false } -func (e *encodeState) reflectValue(v reflect.Value) { - valueEncoder(v)(e, v, false) +func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) { + valueEncoder(v)(e, v, opts) } -type encoderFunc func(e *encodeState, v reflect.Value, quoted bool) +type encOpts struct { + // quoted causes primitive fields to be encoded inside JSON strings. + quoted bool + // escapeHTML causes '<', '>', and '&' to be escaped in JSON strings. + escapeHTML bool +} + +type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts) var encoderCache struct { sync.RWMutex @@ -325,7 +338,7 @@ func typeEncoder(t reflect.Type) encoderFunc { // To deal with recursive types, populate the map with an // indirect func before we build it. This type waits on the - // real func (f) to be ready and then calls it. This indirect + // real func (f) to be ready and then calls it. This indirect // func is only used for recursive types. encoderCache.Lock() if encoderCache.m == nil { @@ -333,9 +346,9 @@ func typeEncoder(t reflect.Type) encoderFunc { } var wg sync.WaitGroup wg.Add(1) - encoderCache.m[t] = func(e *encodeState, v reflect.Value, quoted bool) { + encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) { wg.Wait() - f(e, v, quoted) + f(e, v, opts) } encoderCache.Unlock() @@ -405,11 +418,11 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc { } } -func invalidValueEncoder(e *encodeState, v reflect.Value, quoted bool) { +func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) { e.WriteString("null") } -func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { +func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { if v.Kind() == reflect.Ptr && v.IsNil() { e.WriteString("null") return @@ -418,14 +431,14 @@ func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { b, err := m.MarshalJSON() if err == nil { // copy JSON into buffer, checking validity. - err = compact(&e.Buffer, b, true) + err = compact(&e.Buffer, b, opts.escapeHTML) } if err != nil { e.error(&MarshalerError{v.Type(), err}) } } -func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { +func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) { va := v.Addr() if va.IsNil() { e.WriteString("null") @@ -442,7 +455,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { } } -func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { +func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { if v.Kind() == reflect.Ptr && v.IsNil() { e.WriteString("null") return @@ -452,10 +465,10 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { if err != nil { e.error(&MarshalerError{v.Type(), err}) } - e.stringBytes(b) + e.stringBytes(b, opts.escapeHTML) } -func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { +func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) { va := v.Addr() if va.IsNil() { e.WriteString("null") @@ -466,11 +479,11 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) { if err != nil { e.error(&MarshalerError{v.Type(), err}) } - e.stringBytes(b) + e.stringBytes(b, opts.escapeHTML) } -func boolEncoder(e *encodeState, v reflect.Value, quoted bool) { - if quoted { +func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) { + if opts.quoted { e.WriteByte('"') } if v.Bool() { @@ -478,46 +491,46 @@ func boolEncoder(e *encodeState, v reflect.Value, quoted bool) { } else { e.WriteString("false") } - if quoted { + if opts.quoted { e.WriteByte('"') } } -func intEncoder(e *encodeState, v reflect.Value, quoted bool) { +func intEncoder(e *encodeState, v reflect.Value, opts encOpts) { b := strconv.AppendInt(e.scratch[:0], v.Int(), 10) - if quoted { + if opts.quoted { e.WriteByte('"') } e.Write(b) - if quoted { + if opts.quoted { e.WriteByte('"') } } -func uintEncoder(e *encodeState, v reflect.Value, quoted bool) { +func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) { b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10) - if quoted { + if opts.quoted { e.WriteByte('"') } e.Write(b) - if quoted { + if opts.quoted { e.WriteByte('"') } } type floatEncoder int // number of bits -func (bits floatEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { +func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { f := v.Float() if math.IsInf(f, 0) || math.IsNaN(f) { e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))}) } b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits)) - if quoted { + if opts.quoted { e.WriteByte('"') } e.Write(b) - if quoted { + if opts.quoted { e.WriteByte('"') } } @@ -527,7 +540,7 @@ var ( float64Encoder = (floatEncoder(64)).encode ) -func stringEncoder(e *encodeState, v reflect.Value, quoted bool) { +func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { if v.Type() == numberType { numStr := v.String() // In Go1.5 the empty string encodes to "0", while this is not a valid number literal @@ -541,26 +554,26 @@ func stringEncoder(e *encodeState, v reflect.Value, quoted bool) { e.WriteString(numStr) return } - if quoted { + if opts.quoted { sb, err := Marshal(v.String()) if err != nil { e.error(err) } - e.string(string(sb)) + e.string(string(sb), opts.escapeHTML) } else { - e.string(v.String()) + e.string(v.String(), opts.escapeHTML) } } -func interfaceEncoder(e *encodeState, v reflect.Value, quoted bool) { +func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return } - e.reflectValue(v.Elem()) + e.reflectValue(v.Elem(), opts) } -func unsupportedTypeEncoder(e *encodeState, v reflect.Value, quoted bool) { +func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { e.error(&UnsupportedTypeError{v.Type()}) } @@ -569,7 +582,7 @@ type structEncoder struct { fieldEncs []encoderFunc } -func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { +func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteByte('{') first := true for i, f := range se.fields { @@ -582,9 +595,10 @@ func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { } else { e.WriteByte(',') } - e.string(f.name) + e.string(f.name, opts.escapeHTML) e.WriteByte(':') - se.fieldEncs[i](e, fv, f.quoted) + opts.quoted = f.quoted + se.fieldEncs[i](e, fv, opts) } e.WriteByte('}') } @@ -605,34 +619,50 @@ type mapEncoder struct { elemEnc encoderFunc } -func (me *mapEncoder) encode(e *encodeState, v reflect.Value, _ bool) { +func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return } e.WriteByte('{') - var sv stringValues = v.MapKeys() - sort.Sort(sv) - for i, k := range sv { + + // Extract and sort the keys. + keys := v.MapKeys() + sv := make([]reflectWithString, len(keys)) + for i, v := range keys { + sv[i].v = v + if err := sv[i].resolve(); err != nil { + e.error(&MarshalerError{v.Type(), err}) + } + } + sort.Sort(byString(sv)) + + for i, kv := range sv { if i > 0 { e.WriteByte(',') } - e.string(k.String()) + e.string(kv.s, opts.escapeHTML) e.WriteByte(':') - me.elemEnc(e, v.MapIndex(k), false) + me.elemEnc(e, v.MapIndex(kv.v), opts) } e.WriteByte('}') } func newMapEncoder(t reflect.Type) encoderFunc { - if t.Key().Kind() != reflect.String { - return unsupportedTypeEncoder + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !t.Key().Implements(textMarshalerType) { + return unsupportedTypeEncoder + } } me := &mapEncoder{typeEncoder(t.Elem())} return me.encode } -func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) { +func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) { if v.IsNil() { e.WriteString("null") return @@ -659,18 +689,21 @@ type sliceEncoder struct { arrayEnc encoderFunc } -func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, _ bool) { +func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return } - se.arrayEnc(e, v, false) + se.arrayEnc(e, v, opts) } func newSliceEncoder(t reflect.Type) encoderFunc { // Byte slices get special treatment; arrays don't. if t.Elem().Kind() == reflect.Uint8 { - return encodeByteSlice + p := reflect.PtrTo(t.Elem()) + if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) { + return encodeByteSlice + } } enc := &sliceEncoder{newArrayEncoder(t)} return enc.encode @@ -680,14 +713,14 @@ type arrayEncoder struct { elemEnc encoderFunc } -func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, _ bool) { +func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { if i > 0 { e.WriteByte(',') } - ae.elemEnc(e, v.Index(i), false) + ae.elemEnc(e, v.Index(i), opts) } e.WriteByte(']') } @@ -701,12 +734,12 @@ type ptrEncoder struct { elemEnc encoderFunc } -func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { +func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return } - pe.elemEnc(e, v.Elem(), quoted) + pe.elemEnc(e, v.Elem(), opts) } func newPtrEncoder(t reflect.Type) encoderFunc { @@ -718,11 +751,11 @@ type condAddrEncoder struct { canAddrEnc, elseEnc encoderFunc } -func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) { +func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.CanAddr() { - ce.canAddrEnc(e, v, quoted) + ce.canAddrEnc(e, v, opts) } else { - ce.elseEnc(e, v, quoted) + ce.elseEnc(e, v, opts) } } @@ -775,23 +808,50 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type { return t } -// stringValues is a slice of reflect.Value holding *reflect.StringValue. +type reflectWithString struct { + v reflect.Value + s string +} + +func (w *reflectWithString) resolve() error { + if w.v.Kind() == reflect.String { + w.s = w.v.String() + return nil + } + if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok { + buf, err := tm.MarshalText() + w.s = string(buf) + return err + } + switch w.v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + w.s = strconv.FormatInt(w.v.Int(), 10) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + w.s = strconv.FormatUint(w.v.Uint(), 10) + return nil + } + panic("unexpected map key type") +} + +// byString is a slice of reflectWithString where the reflect.Value is either +// a string or an encoding.TextMarshaler. // It implements the methods to sort by string. -type stringValues []reflect.Value +type byString []reflectWithString -func (sv stringValues) Len() int { return len(sv) } -func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } -func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } -func (sv stringValues) get(i int) string { return sv[i].String() } +func (sv byString) Len() int { return len(sv) } +func (sv byString) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } +func (sv byString) Less(i, j int) bool { return sv[i].s < sv[j].s } // NOTE: keep in sync with stringBytes below. -func (e *encodeState) string(s string) int { +func (e *encodeState) string(s string, escapeHTML bool) int { len0 := e.Len() e.WriteByte('"') start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { + if 0x20 <= b && b != '\\' && b != '"' && + (!escapeHTML || b != '<' && b != '>' && b != '&') { i++ continue } @@ -812,10 +872,11 @@ func (e *encodeState) string(s string) int { e.WriteByte('\\') e.WriteByte('t') default: - // This encodes bytes < 0x20 except for \n and \r, - // as well as <, > and &. The latter are escaped because they - // can lead to security holes when user-controlled strings - // are rendered into JSON and served to some browsers. + // This encodes bytes < 0x20 except for \t, \n and \r. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. e.WriteString(`\u00`) e.WriteByte(hex[b>>4]) e.WriteByte(hex[b&0xF]) @@ -861,13 +922,14 @@ func (e *encodeState) string(s string) int { } // NOTE: keep in sync with string above. -func (e *encodeState) stringBytes(s []byte) int { +func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int { len0 := e.Len() e.WriteByte('"') start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' { + if 0x20 <= b && b != '\\' && b != '"' && + (!escapeHTML || b != '<' && b != '>' && b != '&') { i++ continue } @@ -888,10 +950,11 @@ func (e *encodeState) stringBytes(s []byte) int { e.WriteByte('\\') e.WriteByte('t') default: - // This encodes bytes < 0x20 except for \n and \r, - // as well as <, >, and &. The latter are escaped because they - // can lead to security holes when user-controlled strings - // are rendered into JSON and served to some browsers. + // This encodes bytes < 0x20 except for \t, \n and \r. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. e.WriteString(`\u00`) e.WriteByte(hex[b>>4]) e.WriteByte(hex[b&0xF]) @@ -1169,15 +1232,14 @@ func dominantField(fields []field) (field, bool) { } var fieldCache struct { - sync.RWMutex - m map[reflect.Type][]field + value atomic.Value // map[reflect.Type][]field + mu sync.Mutex // used only by writers } // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. func cachedTypeFields(t reflect.Type) []field { - fieldCache.RLock() - f := fieldCache.m[t] - fieldCache.RUnlock() + m, _ := fieldCache.value.Load().(map[reflect.Type][]field) + f := m[t] if f != nil { return f } @@ -1189,11 +1251,14 @@ func cachedTypeFields(t reflect.Type) []field { f = []field{} } - fieldCache.Lock() - if fieldCache.m == nil { - fieldCache.m = map[reflect.Type][]field{} + fieldCache.mu.Lock() + m, _ = fieldCache.value.Load().(map[reflect.Type][]field) + newM := make(map[reflect.Type][]field, len(m)+1) + for k, v := range m { + newM[k] = v } - fieldCache.m[t] = f - fieldCache.Unlock() + newM[t] = f + fieldCache.value.Store(newM) + fieldCache.mu.Unlock() return f } diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go index c00491e..b484022 100644 --- a/libgo/go/encoding/json/encode_test.go +++ b/libgo/go/encoding/json/encode_test.go @@ -6,6 +6,7 @@ package json import ( "bytes" + "fmt" "math" "reflect" "testing" @@ -375,41 +376,45 @@ func TestDuplicatedFieldDisappears(t *testing.T) { func TestStringBytes(t *testing.T) { // Test that encodeState.stringBytes and encodeState.string use the same encoding. - es := &encodeState{} var r []rune for i := '\u0000'; i <= unicode.MaxRune; i++ { r = append(r, i) } s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too - es.string(s) - esBytes := &encodeState{} - esBytes.stringBytes([]byte(s)) + for _, escapeHTML := range []bool{true, false} { + es := &encodeState{} + es.string(s, escapeHTML) - enc := es.Buffer.String() - encBytes := esBytes.Buffer.String() - if enc != encBytes { - i := 0 - for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] { - i++ - } - enc = enc[i:] - encBytes = encBytes[i:] - i = 0 - for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] { - i++ - } - enc = enc[:len(enc)-i] - encBytes = encBytes[:len(encBytes)-i] + esBytes := &encodeState{} + esBytes.stringBytes([]byte(s), escapeHTML) - if len(enc) > 20 { - enc = enc[:20] + "..." - } - if len(encBytes) > 20 { - encBytes = encBytes[:20] + "..." - } + enc := es.Buffer.String() + encBytes := esBytes.Buffer.String() + if enc != encBytes { + i := 0 + for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] { + i++ + } + enc = enc[i:] + encBytes = encBytes[i:] + i = 0 + for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] { + i++ + } + enc = enc[:len(enc)-i] + encBytes = encBytes[:len(encBytes)-i] + + if len(enc) > 20 { + enc = enc[:20] + "..." + } + if len(encBytes) > 20 { + encBytes = encBytes[:20] + "..." + } - t.Errorf("encodings differ at %#q vs %#q", enc, encBytes) + t.Errorf("with escapeHTML=%t, encodings differ at %#q vs %#q", + escapeHTML, enc, encBytes) + } } } @@ -536,3 +541,73 @@ func TestEncodeString(t *testing.T) { } } } + +type jsonbyte byte + +func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) } + +type textbyte byte + +func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) } + +type jsonint int + +func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) } + +type textint int + +func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) } + +func tenc(format string, a ...interface{}) ([]byte, error) { + var buf bytes.Buffer + fmt.Fprintf(&buf, format, a...) + return buf.Bytes(), nil +} + +// Issue 13783 +func TestEncodeBytekind(t *testing.T) { + testdata := []struct { + data interface{} + want string + }{ + {byte(7), "7"}, + {jsonbyte(7), `{"JB":7}`}, + {textbyte(4), `"TB:4"`}, + {jsonint(5), `{"JI":5}`}, + {textint(1), `"TI:1"`}, + {[]byte{0, 1}, `"AAE="`}, + {[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`}, + {[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`}, + {[]textbyte{2, 3}, `["TB:2","TB:3"]`}, + {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`}, + {[]textint{9, 3}, `["TI:9","TI:3"]`}, + {[]int{9, 3}, `[9,3]`}, + } + for _, d := range testdata { + js, err := Marshal(d.data) + if err != nil { + t.Error(err) + continue + } + got, want := string(js), d.want + if got != want { + t.Errorf("got %s, want %s", got, want) + } + } +} + +func TestTextMarshalerMapKeysAreSorted(t *testing.T) { + b, err := Marshal(map[unmarshalerText]int{ + {"x", "y"}: 1, + {"y", "x"}: 2, + {"a", "z"}: 3, + {"z", "a"}: 4, + }) + if err != nil { + t.Fatalf("Failed to Marshal text.Marshaler: %v", err) + } + const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}` + if string(b) != want { + t.Errorf("Marshal map with text.Marshaler keys: got %#q, want %#q", b, want) + } +} diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go index 7cd9f4d..fba1954 100644 --- a/libgo/go/encoding/json/indent.go +++ b/libgo/go/encoding/json/indent.go @@ -1,4 +1,4 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/json/number_test.go b/libgo/go/encoding/json/number_test.go index 4e63cf9..4b86999 100644 --- a/libgo/go/encoding/json/number_test.go +++ b/libgo/go/encoding/json/number_test.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/json/scanner.go b/libgo/go/encoding/json/scanner.go index ee6622e..a6d8706 100644 --- a/libgo/go/encoding/json/scanner.go +++ b/libgo/go/encoding/json/scanner.go @@ -1,4 +1,4 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -132,7 +132,7 @@ const ( // These values are stored in the parseState stack. // They give the current state of a composite value -// being scanned. If the parser is inside a nested value +// being scanned. If the parser is inside a nested value // the parseState describes the nested state, outermost at entry 0. const ( parseObjectKey = iota // parsing object key (before colon) diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go index 66383ef..70a2897 100644 --- a/libgo/go/encoding/json/scanner_test.go +++ b/libgo/go/encoding/json/scanner_test.go @@ -1,4 +1,4 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go index 8ddcf4d..87f0e57 100644 --- a/libgo/go/encoding/json/stream.go +++ b/libgo/go/encoding/json/stream.go @@ -1,4 +1,4 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -10,7 +10,7 @@ import ( "io" ) -// A Decoder reads and decodes JSON objects from an input stream. +// A Decoder reads and decodes JSON values from an input stream. type Decoder struct { r io.Reader buf []byte @@ -148,7 +148,7 @@ func (dec *Decoder) refill() error { dec.buf = newBuf } - // Read. Delay error for next iteration (after scan). + // Read. Delay error for next iteration (after scan). n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) dec.buf = dec.buf[0 : len(dec.buf)+n] @@ -164,15 +164,20 @@ func nonSpace(b []byte) bool { return false } -// An Encoder writes JSON objects to an output stream. +// An Encoder writes JSON values to an output stream. type Encoder struct { - w io.Writer - err error + w io.Writer + err error + escapeHTML bool + + indentBuf *bytes.Buffer + indentPrefix string + indentValue string } // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w: w} + return &Encoder{w: w, escapeHTML: true} } // Encode writes the JSON encoding of v to the stream, @@ -185,7 +190,7 @@ func (enc *Encoder) Encode(v interface{}) error { return enc.err } e := newEncodeState() - err := e.marshal(v) + err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML}) if err != nil { return err } @@ -198,14 +203,45 @@ func (enc *Encoder) Encode(v interface{}) error { // digits coming. e.WriteByte('\n') - if _, err = enc.w.Write(e.Bytes()); err != nil { + b := e.Bytes() + if enc.indentPrefix != "" || enc.indentValue != "" { + if enc.indentBuf == nil { + enc.indentBuf = new(bytes.Buffer) + } + enc.indentBuf.Reset() + err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue) + if err != nil { + return err + } + b = enc.indentBuf.Bytes() + } + if _, err = enc.w.Write(b); err != nil { enc.err = err } encodeStatePool.Put(e) return err } -// RawMessage is a raw encoded JSON object. +// SetIndent instructs the encoder to format each subsequent encoded +// value as if indented by the package-level function Indent(dst, src, prefix, indent). +// Calling SetIndent("", "") disables indentation. +func (enc *Encoder) SetIndent(prefix, indent string) { + enc.indentPrefix = prefix + enc.indentValue = indent +} + +// SetEscapeHTML specifies whether problematic HTML characters +// should be escaped inside JSON quoted strings. +// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e +// to avoid certain safety problems that can arise when embedding JSON in HTML. +// +// In non-HTML settings where the escaping interferes with the readability +// of the output, SetEscapeHTML(false) disables this behavior. +func (enc *Encoder) SetEscapeHTML(on bool) { + enc.escapeHTML = on +} + +// RawMessage is a raw encoded JSON value. // It implements Marshaler and Unmarshaler and can // be used to delay JSON decoding or precompute a JSON encoding. type RawMessage []byte diff --git a/libgo/go/encoding/json/stream_test.go b/libgo/go/encoding/json/stream_test.go index c2e3040..84edeb1 100644 --- a/libgo/go/encoding/json/stream_test.go +++ b/libgo/go/encoding/json/stream_test.go @@ -1,4 +1,4 @@ -// Copyright 2010 The Go Authors. All rights reserved. +// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -44,6 +44,9 @@ func TestEncoder(t *testing.T) { for i := 0; i <= len(streamTest); i++ { var buf bytes.Buffer enc := NewEncoder(&buf) + // Check that enc.SetIndent("", "") turns off indentation. + enc.SetIndent(">", ".") + enc.SetIndent("", "") for j, v := range streamTest[0:i] { if err := enc.Encode(v); err != nil { t.Fatalf("encode #%d: %v", j, err) @@ -57,6 +60,69 @@ func TestEncoder(t *testing.T) { } } +var streamEncodedIndent = `0.1 +"hello" +null +true +false +[ +>."a", +>."b", +>."c" +>] +{ +>."ß": "long s", +>."K": "Kelvin" +>} +3.14 +` + +func TestEncoderIndent(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + enc.SetIndent(">", ".") + for _, v := range streamTest { + enc.Encode(v) + } + if have, want := buf.String(), streamEncodedIndent; have != want { + t.Error("indented encoding mismatch") + diff(t, []byte(have), []byte(want)) + } +} + +func TestEncoderSetEscapeHTML(t *testing.T) { + var c C + var ct CText + for _, tt := range []struct { + name string + v interface{} + wantEscape string + want string + }{ + {"c", c, `"\u003c\u0026\u003e"`, `"<&>"`}, + {"ct", ct, `"\"\u003c\u0026\u003e\""`, `"\"<&>\""`}, + {`"<&>"`, "<&>", `"\u003c\u0026\u003e"`, `"<&>"`}, + } { + var buf bytes.Buffer + enc := NewEncoder(&buf) + if err := enc.Encode(tt.v); err != nil { + t.Fatalf("Encode(%s): %s", tt.name, err) + } + if got := strings.TrimSpace(buf.String()); got != tt.wantEscape { + t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape) + } + buf.Reset() + enc.SetEscapeHTML(false) + if err := enc.Encode(tt.v); err != nil { + t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err) + } + if got := strings.TrimSpace(buf.String()); got != tt.want { + t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q", + tt.name, got, tt.want) + } + } +} + func TestDecoder(t *testing.T) { for i := 0; i <= len(streamTest); i++ { // Use stream without newlines as input, diff --git a/libgo/go/encoding/json/tagkey_test.go b/libgo/go/encoding/json/tagkey_test.go index 85bb4ba..c1739ea 100644 --- a/libgo/go/encoding/json/tagkey_test.go +++ b/libgo/go/encoding/json/tagkey_test.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/json/tags_test.go b/libgo/go/encoding/json/tags_test.go index 91fb188..8ba8ddd 100644 --- a/libgo/go/encoding/json/tags_test.go +++ b/libgo/go/encoding/json/tags_test.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go index 506196b..ff2bed1 100644 --- a/libgo/go/encoding/pem/pem.go +++ b/libgo/go/encoding/pem/pem.go @@ -150,7 +150,7 @@ func Decode(data []byte) (p *Block, rest []byte) { func decodeError(data, rest []byte) (*Block, []byte) { // If we get here then we have rejected a likely looking, but // ultimately invalid PEM block. We need to start over from a new - // position. We have consumed the preamble line and will have consumed + // position. We have consumed the preamble line and will have consumed // any lines which could be header lines. However, a valid preamble // line is not a valid header line, therefore we cannot have consumed // the preamble line for the any subsequent block. Thus, we will always diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 8ebd693..abb078c 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -26,14 +26,14 @@ const ( // // Marshal handles an array or slice by marshalling each of the elements. // Marshal handles a pointer by marshalling the value it points at or, if the -// pointer is nil, by writing nothing. Marshal handles an interface value by +// pointer is nil, by writing nothing. Marshal handles an interface value by // marshalling the value it contains or, if the interface value is nil, by -// writing nothing. Marshal handles all other data by writing one or more XML +// writing nothing. Marshal handles all other data by writing one or more XML // elements containing the data. // // The name for the XML elements is taken from, in order of preference: // - the tag on the XMLName field, if the data is a struct -// - the value of the XMLName field of type xml.Name +// - the value of the XMLName field of type Name // - the tag of the struct field used to obtain the data // - the name of the struct field used to obtain the data // - the name of the marshalled type @@ -63,7 +63,7 @@ const ( // value were part of the outer struct. // // If a field uses a tag "a>b>c", then the element c will be nested inside -// parent elements a and b. Fields that appear next to each other that name +// parent elements a and b. Fields that appear next to each other that name // the same parent will be enclosed in one XML element. // // See MarshalIndent for an example. @@ -175,10 +175,9 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error { } var ( - begComment = []byte("<!--") - endComment = []byte("-->") - endProcInst = []byte("?>") - endDirective = []byte(">") + begComment = []byte("<!--") + endComment = []byte("-->") + endProcInst = []byte("?>") ) // EncodeToken writes the given XML token to the stream. @@ -217,7 +216,7 @@ func (enc *Encoder) EncodeToken(t Token) error { return p.cachedWriteError() case ProcInst: // First token to be encoded which is also a ProcInst with target of xml - // is the xml declaration. The only ProcInst where target of xml is allowed. + // is the xml declaration. The only ProcInst where target of xml is allowed. if t.Target == "xml" && p.Buffered() != 0 { return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded") } @@ -850,14 +849,14 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { switch k { case reflect.String: s := vf.String() - dashDash = strings.Index(s, "--") >= 0 + dashDash = strings.Contains(s, "--") dashLast = s[len(s)-1] == '-' if !dashDash { p.WriteString(s) } case reflect.Slice: b := vf.Bytes() - dashDash = bytes.Index(b, ddBytes) >= 0 + dashDash = bytes.Contains(b, ddBytes) dashLast = b[len(b)-1] == '-' if !dashDash { p.Write(b) @@ -949,8 +948,8 @@ type parentStack struct { } // trim updates the XML context to match the longest common prefix of the stack -// and the given parents. A closing tag will be written for every parent -// popped. Passing a zero slice or nil will close all the elements. +// and the given parents. A closing tag will be written for every parent +// popped. Passing a zero slice or nil will close all the elements. func (s *parentStack) trim(parents []string) error { split := 0 for ; split < len(parents) && split < len(s.stack); split++ { diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 77b4c7b..937432e 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -27,7 +27,7 @@ import ( // discarded. // // Because Unmarshal uses the reflect package, it can only assign -// to exported (upper case) fields. Unmarshal uses a case-sensitive +// to exported (upper case) fields. Unmarshal uses a case-sensitive // comparison to match XML element names to tag values and struct // field names. // @@ -37,9 +37,9 @@ import ( // // * If the struct has a field of type []byte or string with tag // ",innerxml", Unmarshal accumulates the raw XML nested inside the -// element in that field. The rest of the rules still apply. +// element in that field. The rest of the rules still apply. // -// * If the struct has a field named XMLName of type xml.Name, +// * If the struct has a field named XMLName of type Name, // Unmarshal records the element name in that field. // // * If the XMLName field has an associated tag of the form @@ -59,7 +59,7 @@ import ( // // * If the XML element contains comments, they are accumulated in // the first struct field that has tag ",comment". The struct -// field may have type []byte or string. If there is no such +// field may have type []byte or string. If there is no such // field, the comments are discarded. // // * If the XML element contains a sub-element whose name matches @@ -102,11 +102,11 @@ import ( // // Unmarshal maps an XML element or attribute value to an integer or // floating-point field by setting the field to the result of -// interpreting the string value in decimal. There is no check for +// interpreting the string value in decimal. There is no check for // overflow. // -// Unmarshal maps an XML element to an xml.Name by recording the -// element name. +// Unmarshal maps an XML element to a Name by recording the element +// name. // // Unmarshal maps an XML element to a pointer by setting the pointer // to a freshly allocated value and then mapping the element to that value. @@ -115,13 +115,13 @@ func Unmarshal(data []byte, v interface{}) error { return NewDecoder(bytes.NewReader(data)).Decode(v) } -// Decode works like xml.Unmarshal, except it reads the decoder +// Decode works like Unmarshal, except it reads the decoder // stream to find the start element. func (d *Decoder) Decode(v interface{}) error { return d.DecodeElement(v, nil) } -// DecodeElement works like xml.Unmarshal except that it takes +// DecodeElement works like Unmarshal except that it takes // a pointer to the start XML element to decode into v. // It is useful when a client reads some raw XML tokens itself // but also wants to defer to Unmarshal for some elements. diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 6483c8d..70da962 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index 45f4157..9a3b792 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -219,7 +219,7 @@ func NewDecoder(r io.Reader) *Decoder { // // Slices of bytes in the returned token data refer to the // parser's internal buffer and remain valid only until the next -// call to Token. To acquire a copy of the bytes, call CopyToken +// call to Token. To acquire a copy of the bytes, call CopyToken // or the token's Copy method. // // Token expands self-closing elements such as <br/> @@ -237,10 +237,11 @@ func NewDecoder(r io.Reader) *Decoder { // set to the URL identifying its name space when known. // If Token encounters an unrecognized name space prefix, // it uses the prefix as the Space rather than report an error. -func (d *Decoder) Token() (t Token, err error) { +func (d *Decoder) Token() (Token, error) { + var t Token + var err error if d.stk != nil && d.stk.kind == stkEOF { - err = io.EOF - return + return nil, io.EOF } if d.nextToken != nil { t = d.nextToken @@ -249,7 +250,7 @@ func (d *Decoder) Token() (t Token, err error) { if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF { err = d.syntaxError("unexpected EOF") } - return + return t, err } if !d.Strict { @@ -292,7 +293,7 @@ func (d *Decoder) Token() (t Token, err error) { } t = t1 } - return + return t, err } const xmlURL = "http://www.w3.org/XML/1998/namespace" @@ -331,7 +332,7 @@ func (d *Decoder) switchToReader(r io.Reader) { } // Parsing state - stack holds old name space translations -// and the current set of open elements. The translations to pop when +// and the current set of open elements. The translations to pop when // ending a given tag are *below* it on the stack, which is // more work but forced on us by XML. type stack struct { @@ -1229,7 +1230,7 @@ func isNameString(s string) bool { // These tables were generated by cut and paste from Appendix B of // the XML spec at http://www.xml.com/axml/testaxml.htm -// and then reformatting. First corresponds to (Letter | '_' | ':') +// and then reformatting. First corresponds to (Letter | '_' | ':') // and second corresponds to NameChar. var first = &unicode.RangeTable{ diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index 5d5e4bf..dad6ed9 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -1,4 +1,4 @@ -// Copyright 2009 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -184,8 +184,6 @@ const nonStrictInput = ` <tag>&0a;</tag> ` -var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"} - var nonStrictTokens = []Token{ CharData("\n"), StartElement{Name{"", "tag"}, []Attr{}}, @@ -652,10 +650,6 @@ func TestDisallowedCharacters(t *testing.T) { } } -type procInstEncodingTest struct { - expect, got string -} - var procInstTests = []struct { input string expect [2]string |