aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2014-07-19 08:53:52 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-07-19 08:53:52 +0000
commit00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387 (patch)
treeb988e32ea14a3dc1b4718b1fdfa47bab087ae96c /libgo/go/encoding
parentbcf2fc6ee0a7edbe7de4299f28b66527c07bb0a2 (diff)
downloadgcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.zip
gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.tar.gz
gcc-00d86ac99f5dd6afa5bbd7c38ffe1c585edd2387.tar.bz2
libgo: Update to Go 1.3 release.
From-SVN: r212837
Diffstat (limited to 'libgo/go/encoding')
-rw-r--r--libgo/go/encoding/ascii85/ascii85.go12
-rw-r--r--libgo/go/encoding/ascii85/ascii85_test.go11
-rw-r--r--libgo/go/encoding/asn1/asn1.go8
-rw-r--r--libgo/go/encoding/asn1/marshal.go49
-rw-r--r--libgo/go/encoding/asn1/marshal_test.go9
-rw-r--r--libgo/go/encoding/base32/base32.go12
-rw-r--r--libgo/go/encoding/base64/base64.go39
-rw-r--r--libgo/go/encoding/base64/base64_test.go19
-rw-r--r--libgo/go/encoding/binary/binary.go1
-rw-r--r--libgo/go/encoding/binary/binary_test.go24
-rw-r--r--libgo/go/encoding/gob/decode.go2
-rw-r--r--libgo/go/encoding/gob/decoder.go8
-rw-r--r--libgo/go/encoding/gob/encode.go2
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go19
-rw-r--r--libgo/go/encoding/hex/hex.go3
-rw-r--r--libgo/go/encoding/json/decode.go5
-rw-r--r--libgo/go/encoding/json/indent.go5
-rw-r--r--libgo/go/encoding/json/stream.go3
-rw-r--r--libgo/go/encoding/xml/marshal.go11
-rw-r--r--libgo/go/encoding/xml/marshal_test.go115
-rw-r--r--libgo/go/encoding/xml/read.go9
-rw-r--r--libgo/go/encoding/xml/read_test.go27
-rw-r--r--libgo/go/encoding/xml/typeinfo.go3
-rw-r--r--libgo/go/encoding/xml/xml.go2
24 files changed, 358 insertions, 40 deletions
diff --git a/libgo/go/encoding/ascii85/ascii85.go b/libgo/go/encoding/ascii85/ascii85.go
index e2afc58..60da304 100644
--- a/libgo/go/encoding/ascii85/ascii85.go
+++ b/libgo/go/encoding/ascii85/ascii85.go
@@ -281,6 +281,18 @@ func (d *decoder) Read(p []byte) (n int, err error) {
d.nbuf = copy(d.buf[0:], d.buf[nsrc:d.nbuf])
continue // copy out and return
}
+ if ndst == 0 && d.err == nil {
+ // Special case: input buffer is mostly filled with non-data bytes.
+ // Filter out such bytes to make room for more input.
+ off := 0
+ for i := 0; i < d.nbuf; i++ {
+ if d.buf[i] > ' ' {
+ d.buf[off] = d.buf[i]
+ off++
+ }
+ }
+ d.nbuf = off
+ }
}
// Out of input, out of decoded output. Check errors.
diff --git a/libgo/go/encoding/ascii85/ascii85_test.go b/libgo/go/encoding/ascii85/ascii85_test.go
index 77bc465..aad199b 100644
--- a/libgo/go/encoding/ascii85/ascii85_test.go
+++ b/libgo/go/encoding/ascii85/ascii85_test.go
@@ -197,3 +197,14 @@ func TestBig(t *testing.T) {
t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i)
}
}
+
+func TestDecoderInternalWhitespace(t *testing.T) {
+ s := strings.Repeat(" ", 2048) + "z"
+ decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s)))
+ if err != nil {
+ t.Errorf("Decode gave error %v", err)
+ }
+ if want := []byte("\000\000\000\000"); !bytes.Equal(want, decoded) {
+ t.Errorf("Decode failed: got %v, want %v", decoded, want)
+ }
+}
diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go
index 7a3c379..ec7f91c 100644
--- a/libgo/go/encoding/asn1/asn1.go
+++ b/libgo/go/encoding/asn1/asn1.go
@@ -465,11 +465,15 @@ func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type
if err != nil {
return
}
- // We pretend that various other string types are PRINTABLE STRINGs
- // so that a sequence of them can be parsed into a []string.
switch t.tag {
case tagIA5String, tagGeneralString, tagT61String, tagUTF8String:
+ // We pretend that various other string types are
+ // PRINTABLE STRINGs so that a sequence of them can be
+ // parsed into a []string.
t.tag = tagPrintableString
+ case tagGeneralizedTime, tagUTCTime:
+ // Likewise, both time types are treated the same.
+ t.tag = tagUTCTime
}
if t.class != classUniversal || t.isCompound != compoundType || t.tag != expectedTag {
diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go
index da50cf2..e26fe59 100644
--- a/libgo/go/encoding/asn1/marshal.go
+++ b/libgo/go/encoding/asn1/marshal.go
@@ -295,8 +295,23 @@ func marshalTwoDigits(out *forkableWriter, v int) (err error) {
return out.WriteByte(byte('0' + v%10))
}
+func marshalFourDigits(out *forkableWriter, v int) (err error) {
+ var bytes [4]byte
+ for i := range bytes {
+ bytes[3-i] = '0' + byte(v%10)
+ v /= 10
+ }
+ _, err = out.Write(bytes[:])
+ return
+}
+
+func outsideUTCRange(t time.Time) bool {
+ year := t.Year()
+ return year < 1950 || year >= 2050
+}
+
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
- year, month, day := t.Date()
+ year := t.Year()
switch {
case 1950 <= year && year < 2000:
@@ -310,6 +325,24 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
return
}
+ return marshalTimeCommon(out, t)
+}
+
+func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+ year := t.Year()
+ if year < 0 || year > 9999 {
+ return StructuralError{"cannot represent time as GeneralizedTime"}
+ }
+ if err = marshalFourDigits(out, year); err != nil {
+ return
+ }
+
+ return marshalTimeCommon(out, t)
+}
+
+func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+ _, month, day := t.Date()
+
err = marshalTwoDigits(out, int(month))
if err != nil {
return
@@ -378,7 +411,12 @@ func stripTagAndLength(in []byte) []byte {
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
switch value.Type() {
case timeType:
- return marshalUTCTime(out, value.Interface().(time.Time))
+ t := value.Interface().(time.Time)
+ if outsideUTCRange(t) {
+ return marshalGeneralizedTime(out, t)
+ } else {
+ return marshalUTCTime(out, t)
+ }
case bitStringType:
return marshalBitString(out, value.Interface().(BitString))
case objectIdentifierType:
@@ -504,7 +542,8 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return StructuralError{"explicit string type given to non-string member"}
}
- if tag == tagPrintableString {
+ switch tag {
+ case tagPrintableString:
if params.stringType == 0 {
// This is a string without an explicit string type. We'll use
// a PrintableString if the character set in the string is
@@ -521,6 +560,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
} else {
tag = params.stringType
}
+ case tagUTCTime:
+ if outsideUTCRange(v.Interface().(time.Time)) {
+ tag = tagGeneralizedTime
+ }
}
if params.set {
diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go
index 763c86d..a15acbe 100644
--- a/libgo/go/encoding/asn1/marshal_test.go
+++ b/libgo/go/encoding/asn1/marshal_test.go
@@ -67,6 +67,14 @@ type marshalTest struct {
out string // hex encoded
}
+func farFuture() time.Time {
+ t, err := time.Parse(time.RFC3339, "2100-04-05T12:01:01Z")
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
var marshalTests = []marshalTest{
{10, "02010a"},
{127, "02017f"},
@@ -83,6 +91,7 @@ var marshalTests = []marshalTest{
{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
+ {farFuture(), "180f32313030303430353132303130315a"},
{BitString{[]byte{0x80}, 1}, "03020780"},
{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/libgo/go/encoding/base32/base32.go b/libgo/go/encoding/base32/base32.go
index fe17b73..d770de3 100644
--- a/libgo/go/encoding/base32/base32.go
+++ b/libgo/go/encoding/base32/base32.go
@@ -179,13 +179,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 8 * 5
if nn > len(p) {
nn = len(p)
+ nn -= nn % 5
}
- nn -= nn % 5
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/5*8]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -268,7 +266,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
// valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
// the five valid padding lengths, and Section 9 "Illustrations and
- // Examples" for an illustration for how the the 1st, 3rd and 6th base32
+ // Examples" for an illustration for how the 1st, 3rd and 6th base32
// src bytes do not yield enough information to decode a dst byte.
if dlen == 1 || dlen == 3 || dlen == 6 {
return n, false, CorruptInputError(olen - len(src) - 1)
diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go
index 85e398f..e38c26d 100644
--- a/libgo/go/encoding/base64/base64.go
+++ b/libgo/go/encoding/base64/base64.go
@@ -159,13 +159,11 @@ func (e *encoder) Write(p []byte) (n int, err error) {
nn := len(e.out) / 4 * 3
if nn > len(p) {
nn = len(p)
+ nn -= nn % 3
}
- nn -= nn % 3
- if nn > 0 {
- e.enc.Encode(e.out[0:], p[0:nn])
- if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
- return n, e.err
- }
+ e.enc.Encode(e.out[0:], p[0:nn])
+ if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
+ return n, e.err
}
n += nn
p = p[nn:]
@@ -226,21 +224,33 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
var dbuf [4]byte
dlen := 4
- for j := 0; j < 4; {
+ for j := range dbuf {
if len(src) == 0 {
return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '=' && j >= 2 && len(src) < 4 {
+ if in == '=' {
// We've reached the end and there's padding
- if len(src)+j < 4-1 {
- // not enough padding
- return n, false, CorruptInputError(olen)
- }
- if len(src) > 0 && src[0] != '=' {
+ switch j {
+ case 0, 1:
// incorrect padding
return n, false, CorruptInputError(olen - len(src) - 1)
+ case 2:
+ // "==" is expected, the first "=" is already consumed.
+ if len(src) == 0 {
+ // not enough padding
+ return n, false, CorruptInputError(olen)
+ }
+ if src[0] != '=' {
+ // incorrect padding
+ return n, false, CorruptInputError(olen - len(src) - 1)
+ }
+ src = src[1:]
+ }
+ if len(src) > 0 {
+ // trailing garbage
+ err = CorruptInputError(olen - len(src))
}
dlen, end = j, true
break
@@ -249,7 +259,6 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
if dbuf[j] == 0xFF {
return n, false, CorruptInputError(olen - len(src) - 1)
}
- j++
}
// Pack 4x 6-bit source blocks into 3 byte destination
@@ -268,7 +277,7 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
n += dlen - 1
}
- return n, end, nil
+ return n, end, err
}
// Decode decodes src using the encoding enc. It writes at most
diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go
index 6bcc724..a075194 100644
--- a/libgo/go/encoding/base64/base64_test.go
+++ b/libgo/go/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "reflect"
"strings"
"testing"
"time"
@@ -149,9 +150,13 @@ func TestDecodeCorrupt(t *testing.T) {
}{
{"", -1},
{"!!!!", 0},
+ {"====", 0},
{"x===", 1},
+ {"=AAA", 0},
+ {"A=AA", 1},
{"AA=A", 2},
- {"AAA=AAAA", 3},
+ {"AA==A", 4},
+ {"AAA=AAAA", 4},
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
@@ -161,6 +166,7 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAA=", -1},
{"AAAA", -1},
{"AAAAAA=", 7},
+ {"YWJjZA=====", 8},
}
for _, tc := range testCases {
dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
@@ -325,3 +331,14 @@ bqbPb06551Y4
t.Error("Decoded results not equal")
}
}
+
+func TestDecoderIssue7733(t *testing.T) {
+ s, err := StdEncoding.DecodeString("YWJjZA=====")
+ want := CorruptInputError(8)
+ if !reflect.DeepEqual(want, err) {
+ t.Errorf("Error = %v; want CorruptInputError(8)", err)
+ }
+ if string(s) != "abcd" {
+ t.Errorf("DecodeString = %q; want abcd", s)
+ }
+}
diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go
index f3466b9..a569487 100644
--- a/libgo/go/encoding/binary/binary.go
+++ b/libgo/go/encoding/binary/binary.go
@@ -133,6 +133,7 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
+// When reading into a struct, all non-blank fields must be exported.
func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Fast path for basic types and slices.
if n := intDataSize(data); n != 0 {
diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go
index 1aa6ecd..c80c903 100644
--- a/libgo/go/encoding/binary/binary_test.go
+++ b/libgo/go/encoding/binary/binary_test.go
@@ -265,6 +265,30 @@ 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
+// anything else would be an API change.
+
+type Unexported struct {
+ a int32
+}
+
+func TestUnexportedRead(t *testing.T) {
+ var buf bytes.Buffer
+ u1 := Unexported{a: 1}
+ if err := Write(&buf, LittleEndian, &u1); err != nil {
+ t.Fatal(err)
+ }
+
+ defer func() {
+ if recover() == nil {
+ t.Fatal("did not panic")
+ }
+ }()
+ var u2 Unexported
+ Read(&buf, LittleEndian, &u2)
+}
+
type byteSliceReader struct {
remain []byte
}
diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go
index aa186a5..d851314 100644
--- a/libgo/go/encoding/gob/decode.go
+++ b/libgo/go/encoding/gob/decode.go
@@ -685,7 +685,7 @@ func (dec *Decoder) ignoreSlice(state *decoderState, elemOp decOp) {
// but first it checks that the assignment will succeed.
func setInterfaceValue(ivalue reflect.Value, value reflect.Value) {
if !value.Type().AssignableTo(ivalue.Type()) {
- errorf("cannot assign value of type %s to %s", value.Type(), ivalue.Type())
+ errorf("%s is not assignable to type %s", value.Type(), ivalue.Type())
}
ivalue.Set(value)
}
diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go
index 04f706c..3a769ec 100644
--- a/libgo/go/encoding/gob/decoder.go
+++ b/libgo/go/encoding/gob/decoder.go
@@ -183,11 +183,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
return -1
}
-// Decode reads the next value from the connection and stores
+// Decode reads the next value from the input stream and stores
// it in the data represented by the empty interface value.
// If e is nil, the value will be discarded. Otherwise,
// the value underlying e must be a pointer to the
// correct type for the next data item received.
+// If the input is at EOF, Decode returns io.EOF and
+// does not modify e.
func (dec *Decoder) Decode(e interface{}) error {
if e == nil {
return dec.DecodeValue(reflect.Value{})
@@ -202,10 +204,12 @@ func (dec *Decoder) Decode(e interface{}) error {
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection.
+// 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
// 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 e.
func (dec *Decoder) DecodeValue(v reflect.Value) error {
if v.IsValid() {
if v.Kind() == reflect.Ptr && !v.IsNil() {
diff --git a/libgo/go/encoding/gob/encode.go b/libgo/go/encoding/gob/encode.go
index d158b64..7831c02 100644
--- a/libgo/go/encoding/gob/encode.go
+++ b/libgo/go/encoding/gob/encode.go
@@ -491,7 +491,7 @@ func isZero(val reflect.Value) bool {
return !val.Bool()
case reflect.Complex64, reflect.Complex128:
return val.Complex() == 0
- case reflect.Chan, reflect.Func, reflect.Ptr:
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr:
return val.IsNil()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return val.Int() == 0
diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go
index 0193e2b..157b772 100644
--- a/libgo/go/encoding/gob/gobencdec_test.go
+++ b/libgo/go/encoding/gob/gobencdec_test.go
@@ -705,13 +705,14 @@ func TestGobEncoderExtraIndirect(t *testing.T) {
}
// Another bug: this caused a crash with the new Go1 Time type.
-// We throw in a gob-encoding array, to test another case of isZero
-
+// We throw in a gob-encoding array, to test another case of isZero,
+// and a struct containing an nil interface, to test a third.
type isZeroBug struct {
T time.Time
S string
I int
A isZeroBugArray
+ F isZeroBugInterface
}
type isZeroBugArray [2]uint8
@@ -731,8 +732,20 @@ func (a *isZeroBugArray) GobDecode(data []byte) error {
return nil
}
+type isZeroBugInterface struct {
+ I interface{}
+}
+
+func (i isZeroBugInterface) GobEncode() (b []byte, e error) {
+ return []byte{}, nil
+}
+
+func (i *isZeroBugInterface) GobDecode(data []byte) error {
+ return nil
+}
+
func TestGobEncodeIsZero(t *testing.T) {
- x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}}
+ x := isZeroBug{time.Now(), "hello", -55, isZeroBugArray{1, 2}, isZeroBugInterface{}}
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(x)
diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go
index 167d00e..d1fc702 100644
--- a/libgo/go/encoding/hex/hex.go
+++ b/libgo/go/encoding/hex/hex.go
@@ -146,6 +146,9 @@ func (h *dumper) Write(data []byte) (n int, err error) {
h.buf[12] = ' '
h.buf[13] = ' '
_, err = h.w.Write(h.buf[4:])
+ if err != nil {
+ return
+ }
}
Encode(h.buf[:], data[i:i+1])
h.buf[2] = ' '
diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go
index dde0d78..af1c908 100644
--- a/libgo/go/encoding/json/decode.go
+++ b/libgo/go/encoding/json/decode.go
@@ -54,6 +54,11 @@ import (
// If no more serious errors are encountered, Unmarshal returns
// an UnmarshalTypeError describing the earliest such error.
//
+// The JSON null value unmarshals into an interface, map, pointer, or slice
+// by setting that Go value to nil. Because null is often used in JSON to mean
+// ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+// on the value and produces no error.
+//
// When unmarshaling quoted strings, invalid UTF-8 or
// invalid UTF-16 surrogate pairs are not treated as an error.
// Instead, they are replaced by the Unicode replacement
diff --git a/libgo/go/encoding/json/indent.go b/libgo/go/encoding/json/indent.go
index 11ef709..e1bacaf 100644
--- a/libgo/go/encoding/json/indent.go
+++ b/libgo/go/encoding/json/indent.go
@@ -69,8 +69,9 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
// Each element in a JSON object or array begins on a new,
// indented line beginning with prefix followed by one or more
// copies of indent according to the indentation nesting.
-// The data appended to dst has no trailing newline, to make it easier
-// to embed inside other formatted JSON data.
+// The data appended to dst does not begin with the prefix nor
+// any indentation, and has no trailing newline, to make it
+// easier to embed inside other formatted JSON data.
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
origLen := dst.Len()
var scan scanner
diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go
index e8d6bd4..1cb289f 100644
--- a/libgo/go/encoding/json/stream.go
+++ b/libgo/go/encoding/json/stream.go
@@ -148,7 +148,8 @@ func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w}
}
-// Encode writes the JSON encoding of v to the stream.
+// Encode writes the JSON encoding of v to the stream,
+// followed by a newline character.
//
// See the documentation for Marshal for details about the
// conversion of Go values to JSON.
diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go
index d9522e0..8c63420 100644
--- a/libgo/go/encoding/xml/marshal.go
+++ b/libgo/go/encoding/xml/marshal.go
@@ -184,10 +184,12 @@ var (
// EncodeToken does not call Flush, because usually it is part of a larger operation
// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
// during those), and those will call Flush when finished.
-//
// Callers that create an Encoder and then invoke EncodeToken directly, without
// using Encode or EncodeElement, need to call Flush when finished to ensure
// that the XML is written to the underlying writer.
+//
+// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
+// in the stream.
func (enc *Encoder) EncodeToken(t Token) error {
p := &enc.p
switch t := t.(type) {
@@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
p.WriteString("-->")
return p.cachedWriteError()
case ProcInst:
- if t.Target == "xml" || !isNameString(t.Target) {
+ // 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.
+ if t.Target == "xml" && p.Buffered() != 0 {
+ return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
+ }
+ if !isNameString(t.Target) {
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
}
if bytes.Contains(t.Inst, endProcInst) {
diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go
index d34118a..14f73a7 100644
--- a/libgo/go/encoding/xml/marshal_test.go
+++ b/libgo/go/encoding/xml/marshal_test.go
@@ -314,6 +314,31 @@ type MarshalerStruct struct {
Foo MyMarshalerAttrTest `xml:",attr"`
}
+type InnerStruct struct {
+ XMLName Name `xml:"testns outer"`
+}
+
+type OuterStruct struct {
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedStruct struct {
+ InnerStruct
+ XMLName Name `xml:"outerns test"`
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterNamedOrderedStruct struct {
+ XMLName Name `xml:"outerns test"`
+ InnerStruct
+ IntAttr int `xml:"int,attr"`
+}
+
+type OuterOuterStruct struct {
+ OuterStruct
+}
+
func ifaceptr(x interface{}) interface{} {
return &x
}
@@ -883,6 +908,22 @@ var marshalTests = []struct {
ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
Value: &MarshalerStruct{},
},
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterStruct{IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<test xmlns="outerns" int="10"></test>`,
+ Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
+ },
+ {
+ ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
+ Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
+ },
}
func TestMarshal(t *testing.T) {
@@ -1149,3 +1190,77 @@ func TestStructPointerMarshal(t *testing.T) {
t.Fatal(err)
}
}
+
+var encodeTokenTests = []struct {
+ tok Token
+ want string
+ ok bool
+}{
+ {StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
+ {StartElement{Name{"space", ""}, nil}, "", false},
+ {EndElement{Name{"space", ""}}, "", false},
+ {CharData("foo"), "foo", true},
+ {Comment("foo"), "<!--foo-->", true},
+ {Comment("foo-->"), "", false},
+ {ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
+ {ProcInst{"", []byte("Instruction")}, "", false},
+ {ProcInst{"Target", []byte("Instruction?>")}, "", false},
+ {Directive("foo"), "<!foo>", true},
+ {Directive("foo>"), "", false},
+}
+
+func TestEncodeToken(t *testing.T) {
+ for _, tt := range encodeTokenTests {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+ err := enc.EncodeToken(tt.tok)
+ switch {
+ case !tt.ok && err == nil:
+ t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
+ case tt.ok && err != nil:
+ t.Fatalf("enc.EncodeToken: %v", err)
+ case !tt.ok && err != nil:
+ // expected error, got one
+ }
+ if err := enc.Flush(); err != nil {
+ t.Fatalf("enc.EncodeToken: %v", err)
+ }
+ if got := buf.String(); got != tt.want {
+ t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+ }
+ }
+}
+
+func TestProcInstEncodeToken(t *testing.T) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
+ }
+
+ if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
+ t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
+ }
+
+ if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
+ t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
+ }
+}
+
+func TestDecodeEncode(t *testing.T) {
+ var in, out bytes.Buffer
+ in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
+<?Target Instruction?>
+<root>
+</root>
+`)
+ dec := NewDecoder(&in)
+ enc := NewEncoder(&out)
+ for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
+ err = enc.EncodeToken(tok)
+ if err != nil {
+ t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
+ }
+ }
+}
diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go
index 651d13d4..75b9f2b 100644
--- a/libgo/go/encoding/xml/read.go
+++ b/libgo/go/encoding/xml/read.go
@@ -284,6 +284,15 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
}
+ // Load value from interface, but only if the result will be
+ // usefully addressable.
+ if val.Kind() == reflect.Interface && !val.IsNil() {
+ e := val.Elem()
+ if e.Kind() == reflect.Ptr && !e.IsNil() {
+ val = e
+ }
+ }
+
if val.Kind() == reflect.Ptr {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go
index 1404c90..01f55d0 100644
--- a/libgo/go/encoding/xml/read_test.go
+++ b/libgo/go/encoding/xml/read_test.go
@@ -685,3 +685,30 @@ func TestUnmarshaler(t *testing.T) {
t.Errorf("m=%#+v\n", m)
}
}
+
+type Pea struct {
+ Cotelydon string
+}
+
+type Pod struct {
+ Pea interface{} `xml:"Pea"`
+}
+
+// https://code.google.com/p/go/issues/detail?id=6836
+func TestUnmarshalIntoInterface(t *testing.T) {
+ pod := new(Pod)
+ pod.Pea = new(Pea)
+ xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>`
+ err := Unmarshal([]byte(xml), pod)
+ if err != nil {
+ t.Fatalf("failed to unmarshal %q: %v", xml, err)
+ }
+ pea, ok := pod.Pea.(*Pea)
+ if !ok {
+ t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+ }
+ have, want := pea.Cotelydon, "Green stuff"
+ if have != want {
+ t.Errorf("failed to unmarshal into interface, have %q want %q", have, want)
+ }
+}
diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go
index 83e6540..22248d2 100644
--- a/libgo/go/encoding/xml/typeinfo.go
+++ b/libgo/go/encoding/xml/typeinfo.go
@@ -75,6 +75,9 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
if err != nil {
return nil, err
}
+ if tinfo.xmlname == nil {
+ tinfo.xmlname = inner.xmlname
+ }
for _, finfo := range inner.fields {
finfo.idx = append([]int{i}, finfo.idx...)
if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go
index 5b9d670..b473cb8 100644
--- a/libgo/go/encoding/xml/xml.go
+++ b/libgo/go/encoding/xml/xml.go
@@ -200,6 +200,8 @@ type Decoder struct {
}
// NewDecoder creates a new XML parser reading from r.
+// If r does not implement io.ByteReader, NewDecoder will
+// do its own buffering.
func NewDecoder(r io.Reader) *Decoder {
d := &Decoder{
ns: make(map[string]string),