diff options
Diffstat (limited to 'libgo/go/encoding')
-rw-r--r-- | libgo/go/encoding/binary/varint.go | 19 | ||||
-rw-r--r-- | libgo/go/encoding/binary/varint_test.go | 32 | ||||
-rw-r--r-- | libgo/go/encoding/git85/git.go | 276 | ||||
-rw-r--r-- | libgo/go/encoding/git85/git_test.go | 194 | ||||
-rw-r--r-- | libgo/go/encoding/gob/debug.go | 3 | ||||
-rw-r--r-- | libgo/go/encoding/gob/decoder.go | 4 | ||||
-rw-r--r-- | libgo/go/encoding/gob/gobencdec_test.go | 1 | ||||
-rw-r--r-- | libgo/go/encoding/xml/marshal.go | 129 | ||||
-rw-r--r-- | libgo/go/encoding/xml/marshal_test.go | 102 | ||||
-rw-r--r-- | libgo/go/encoding/xml/read.go | 80 | ||||
-rw-r--r-- | libgo/go/encoding/xml/read_test.go | 9 | ||||
-rw-r--r-- | libgo/go/encoding/xml/typeinfo.go | 3 | ||||
-rw-r--r-- | libgo/go/encoding/xml/xml.go | 482 | ||||
-rw-r--r-- | libgo/go/encoding/xml/xml_test.go | 81 |
14 files changed, 486 insertions, 929 deletions
diff --git a/libgo/go/encoding/binary/varint.go b/libgo/go/encoding/binary/varint.go index d4872ee..b756afd 100644 --- a/libgo/go/encoding/binary/varint.go +++ b/libgo/go/encoding/binary/varint.go @@ -37,6 +37,7 @@ const ( ) // PutUvarint encodes a uint64 into buf and returns the number of bytes written. +// If the buffer is too small, PutUvarint will panic. func PutUvarint(buf []byte, x uint64) int { i := 0 for x >= 0x80 { @@ -73,6 +74,7 @@ func Uvarint(buf []byte) (uint64, int) { } // PutVarint encodes an int64 into buf and returns the number of bytes written. +// If the buffer is too small, PutVarint will panic. func PutVarint(buf []byte, x int64) int { ux := uint64(x) << 1 if x < 0 { @@ -98,14 +100,6 @@ func Varint(buf []byte) (int64, int) { return x, n } -// WriteUvarint encodes x and writes the result to w. -func WriteUvarint(w io.Writer, x uint64) error { - var buf [MaxVarintLen64]byte - n := PutUvarint(buf[:], x) - _, err := w.Write(buf[0:n]) - return err -} - var overflow = errors.New("binary: varint overflows a 64-bit integer") // ReadUvarint reads an encoded unsigned integer from r and returns it as a uint64. @@ -129,15 +123,6 @@ func ReadUvarint(r io.ByteReader) (uint64, error) { panic("unreachable") } -// WriteVarint encodes x and writes the result to w. -func WriteVarint(w io.Writer, x int64) error { - ux := uint64(x) << 1 - if x < 0 { - ux = ^ux - } - return WriteUvarint(w, ux) -} - // ReadVarint reads an encoded unsigned integer from r and returns it as a uint64. func ReadVarint(r io.ByteReader) (int64, error) { ux, err := ReadUvarint(r) // ok to continue in presence of error diff --git a/libgo/go/encoding/binary/varint_test.go b/libgo/go/encoding/binary/varint_test.go index dc550f2..9476bd5 100644 --- a/libgo/go/encoding/binary/varint_test.go +++ b/libgo/go/encoding/binary/varint_test.go @@ -25,9 +25,9 @@ func TestConstants(t *testing.T) { } func testVarint(t *testing.T, x int64) { - buf1 := make([]byte, MaxVarintLen64) - n := PutVarint(buf1[:], x) - y, m := Varint(buf1[0:n]) + buf := make([]byte, MaxVarintLen64) + n := PutVarint(buf, x) + y, m := Varint(buf[0:n]) if x != y { t.Errorf("Varint(%d): got %d", x, y) } @@ -35,15 +35,7 @@ func testVarint(t *testing.T, x int64) { t.Errorf("Varint(%d): got n = %d; want %d", x, m, n) } - var buf2 bytes.Buffer - err := WriteVarint(&buf2, x) - if err != nil { - t.Errorf("WriteVarint(%d): %s", x, err) - } - if n != buf2.Len() { - t.Errorf("WriteVarint(%d): got n = %d; want %d", x, buf2.Len(), n) - } - y, err = ReadVarint(&buf2) + y, err := ReadVarint(bytes.NewBuffer(buf)) if err != nil { t.Errorf("ReadVarint(%d): %s", x, err) } @@ -53,9 +45,9 @@ func testVarint(t *testing.T, x int64) { } func testUvarint(t *testing.T, x uint64) { - buf1 := make([]byte, MaxVarintLen64) - n := PutUvarint(buf1[:], x) - y, m := Uvarint(buf1[0:n]) + buf := make([]byte, MaxVarintLen64) + n := PutUvarint(buf, x) + y, m := Uvarint(buf[0:n]) if x != y { t.Errorf("Uvarint(%d): got %d", x, y) } @@ -63,15 +55,7 @@ func testUvarint(t *testing.T, x uint64) { t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n) } - var buf2 bytes.Buffer - err := WriteUvarint(&buf2, x) - if err != nil { - t.Errorf("WriteUvarint(%d): %s", x, err) - } - if n != buf2.Len() { - t.Errorf("WriteUvarint(%d): got n = %d; want %d", x, buf2.Len(), n) - } - y, err = ReadUvarint(&buf2) + y, err := ReadUvarint(bytes.NewBuffer(buf)) if err != nil { t.Errorf("ReadUvarint(%d): %s", x, err) } diff --git a/libgo/go/encoding/git85/git.go b/libgo/go/encoding/git85/git.go deleted file mode 100644 index d383213..0000000 --- a/libgo/go/encoding/git85/git.go +++ /dev/null @@ -1,276 +0,0 @@ -// 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. - -// Package git85 implements the radix 85 data encoding -// used in the Git version control system. -package git85 - -import ( - "bytes" - "io" - "strconv" -) - -type CorruptInputError int64 - -func (e CorruptInputError) Error() string { - return "illegal git85 data at input byte " + strconv.FormatInt(int64(e), 10) -} - -const encode = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~" - -// The decodings are 1+ the actual value, so that the -// default zero value can be used to mean "not valid". -var decode = [256]uint8{ - '0': 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 'A': 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 'a': 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, - '!': 63, - '#': 64, 65, 66, 67, - '(': 68, 69, 70, 71, - '-': 72, - ';': 73, - '<': 74, 75, 76, 77, - '@': 78, - '^': 79, 80, 81, - '{': 82, 83, 84, 85, -} - -// Encode encodes src into EncodedLen(len(src)) -// 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 the radix 85 encoding used in the -// Git version control tool. -// -// The encoding splits src into chunks of at most 52 bytes -// and encodes each chunk on its own line. -func Encode(dst, src []byte) int { - ndst := 0 - for len(src) > 0 { - n := len(src) - if n > 52 { - n = 52 - } - if n <= 27 { - dst[ndst] = byte('A' + n - 1) - } else { - dst[ndst] = byte('a' + n - 26 - 1) - } - ndst++ - for i := 0; i < n; i += 4 { - var v uint32 - for j := 0; j < 4 && i+j < n; j++ { - v |= uint32(src[i+j]) << uint(24-j*8) - } - for j := 4; j >= 0; j-- { - dst[ndst+j] = encode[v%85] - v /= 85 - } - ndst += 5 - } - dst[ndst] = '\n' - ndst++ - src = src[n:] - } - return ndst -} - -// EncodedLen returns the length of an encoding of n source bytes. -func EncodedLen(n int) int { - if n == 0 { - return 0 - } - // 5 bytes per 4 bytes of input, rounded up. - // 2 extra bytes for each line of 52 src bytes, rounded up. - return (n+3)/4*5 + (n+51)/52*2 -} - -var newline = []byte{'\n'} - -// Decode decodes src into at most MaxDecodedLen(len(src)) -// bytes, returning the actual number of bytes written to dst. -// -// If Decode encounters invalid input, it returns a CorruptInputError. -// -func Decode(dst, src []byte) (n int, err error) { - ndst := 0 - nsrc := 0 - for nsrc < len(src) { - var l int - switch ch := int(src[nsrc]); { - case 'A' <= ch && ch <= 'Z': - l = ch - 'A' + 1 - case 'a' <= ch && ch <= 'z': - l = ch - 'a' + 26 + 1 - default: - return ndst, CorruptInputError(nsrc) - } - if nsrc+1+l > len(src) { - return ndst, CorruptInputError(nsrc) - } - el := (l + 3) / 4 * 5 // encoded len - if nsrc+1+el+1 > len(src) || src[nsrc+1+el] != '\n' { - return ndst, CorruptInputError(nsrc) - } - line := src[nsrc+1 : nsrc+1+el] - for i := 0; i < el; i += 5 { - var v uint32 - for j := 0; j < 5; j++ { - ch := decode[line[i+j]] - if ch == 0 { - return ndst, CorruptInputError(nsrc + 1 + i + j) - } - v = v*85 + uint32(ch-1) - } - for j := 0; j < 4; j++ { - dst[ndst] = byte(v >> 24) - v <<= 8 - ndst++ - } - } - // Last fragment may have run too far (but there was room in dst). - // Back up. - if l%4 != 0 { - ndst -= 4 - l%4 - } - nsrc += 1 + el + 1 - } - return ndst, nil -} - -func MaxDecodedLen(n int) int { return n / 5 * 4 } - -// NewEncoder returns a new Git base85 stream encoder. Data written to -// the returned writer will be encoded and then written to w. -// The Git encoding operates on 52-byte blocks; when finished -// writing, the caller must Close the returned encoder to flush any -// partially written blocks. -func NewEncoder(w io.Writer) io.WriteCloser { return &encoder{w: w} } - -type encoder struct { - w io.Writer - err error - buf [52]byte - nbuf int - out [1024]byte - nout int -} - -func (e *encoder) Write(p []byte) (n int, err error) { - if e.err != nil { - return 0, e.err - } - - // Leading fringe. - if e.nbuf > 0 { - var i int - for i = 0; i < len(p) && e.nbuf < 52; i++ { - e.buf[e.nbuf] = p[i] - e.nbuf++ - } - n += i - p = p[i:] - if e.nbuf < 52 { - return - } - nout := Encode(e.out[0:], e.buf[0:]) - if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil { - return n, e.err - } - e.nbuf = 0 - } - - // Large interior chunks. - for len(p) >= 52 { - nn := len(e.out) / (1 + 52/4*5 + 1) * 52 - if nn > len(p) { - nn = len(p) / 52 * 52 - } - if nn > 0 { - nout := Encode(e.out[0:], p[0:nn]) - if _, e.err = e.w.Write(e.out[0:nout]); e.err != nil { - return n, e.err - } - } - n += nn - p = p[nn:] - } - - // Trailing fringe. - for i := 0; i < len(p); i++ { - e.buf[i] = p[i] - } - e.nbuf = len(p) - n += len(p) - return -} - -func (e *encoder) Close() error { - // If there's anything left in the buffer, flush it out - if e.err == nil && e.nbuf > 0 { - nout := Encode(e.out[0:], e.buf[0:e.nbuf]) - e.nbuf = 0 - _, e.err = e.w.Write(e.out[0:nout]) - } - return e.err -} - -// NewDecoder returns a new Git base85 stream decoder. -func NewDecoder(r io.Reader) io.Reader { return &decoder{r: r} } - -type decoder struct { - r io.Reader - err error - readErr error - buf [1024]byte - nbuf int - out []byte - outbuf [1024]byte - off int64 -} - -func (d *decoder) Read(p []byte) (n int, err error) { - if len(p) == 0 { - return 0, nil - } - - for { - // Copy leftover output from last decode. - if len(d.out) > 0 { - n = copy(p, d.out) - d.out = d.out[n:] - return - } - - // Out of decoded output. Check errors. - if d.err != nil { - return 0, d.err - } - if d.readErr != nil { - d.err = d.readErr - return 0, d.err - } - - // Read and decode more input. - var nn int - nn, d.readErr = d.r.Read(d.buf[d.nbuf:]) - d.nbuf += nn - - // Send complete lines to Decode. - nl := bytes.LastIndex(d.buf[0:d.nbuf], newline) - if nl < 0 { - continue - } - nn, d.err = Decode(d.outbuf[0:], d.buf[0:nl+1]) - if e, ok := d.err.(CorruptInputError); ok { - d.err = CorruptInputError(int64(e) + d.off) - } - d.out = d.outbuf[0:nn] - d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf]) - d.off += int64(nl + 1) - } - panic("unreachable") -} diff --git a/libgo/go/encoding/git85/git_test.go b/libgo/go/encoding/git85/git_test.go deleted file mode 100644 index 81f5b0e..0000000 --- a/libgo/go/encoding/git85/git_test.go +++ /dev/null @@ -1,194 +0,0 @@ -// 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. - -package git85 - -import ( - "bytes" - "io" - "io/ioutil" - "testing" -) - -type testpair struct { - decoded, encoded string -} - -func testEqual(t *testing.T, msg string, args ...interface{}) bool { - if args[len(args)-2] != args[len(args)-1] { - t.Errorf(msg, args...) - return false - } - return true -} - -func TestGitTable(t *testing.T) { - var saw [256]bool - for i, c := range encode { - if decode[c] != uint8(i+1) { - t.Errorf("decode['%c'] = %d, want %d", c, decode[c], i+1) - } - saw[c] = true - } - for i, b := range saw { - if !b && decode[i] != 0 { - t.Errorf("decode[%d] = %d, want 0", i, decode[i]) - } - } -} - -var gitPairs = []testpair{ - // Wikipedia example, adapted. - { - "Man is distinguished, not only by his reason, but by this singular passion from " + - "other animals, which is a lust of the mind, that by a perseverance of delight in " + - "the continued and indefatigable generation of knowledge, exceeds the short " + - "vehemence of any carnal pleasure.", - - "zO<`^zX>%ZCX>)XGZfA9Ab7*B`EFf-gbRchTY<VDJc_3(Mb0BhMVRLV8EFfZabRc4R\n" + - "zAarPHb0BkRZfA9DVR9gFVRLh7Z*CxFa&K)QZ**v7av))DX>DO_b1WctXlY|;AZc?T\n" + - "zVIXXEb95kYW*~HEWgu;7Ze%PVbZB98AYyqSVIXj2a&u*NWpZI|V`U(3W*}r`Y-wj`\n" + - "zbRcPNAarPDAY*TCbZKsNWn>^>Ze$>7Ze(R<VRUI{VPb4$AZKN6WpZJ3X>V>IZ)PBC\n" + - "zZf|#NWn^b%EFfigV`XJzb0BnRWgv5CZ*p`Xc4cT~ZDnp_Wgu^6AYpEKAY);2ZeeU7\n" + - "IaBO8^b9HiME&u=k\n", - }, -} - -var gitBigtest = gitPairs[len(gitPairs)-1] - -func TestEncode(t *testing.T) { - for _, p := range gitPairs { - buf := make([]byte, EncodedLen(len(p.decoded))) - n := Encode(buf, []byte(p.decoded)) - if n != len(buf) { - t.Errorf("EncodedLen does not agree with Encode") - } - buf = buf[0:n] - testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded) - } -} - -func TestEncoder(t *testing.T) { - for _, p := range gitPairs { - bb := &bytes.Buffer{} - encoder := NewEncoder(bb) - encoder.Write([]byte(p.decoded)) - encoder.Close() - testEqual(t, "Encode(%q) = %q, want %q", p.decoded, bb.String(), p.encoded) - } -} - -func TestEncoderBuffering(t *testing.T) { - input := []byte(gitBigtest.decoded) - for bs := 1; bs <= 12; bs++ { - bb := &bytes.Buffer{} - encoder := NewEncoder(bb) - for pos := 0; pos < len(input); pos += bs { - end := pos + bs - if end > len(input) { - end = len(input) - } - n, err := encoder.Write(input[pos:end]) - testEqual(t, "Write(%q) gave error %v, want %v", input[pos:end], err, error(nil)) - testEqual(t, "Write(%q) gave length %v, want %v", input[pos:end], n, end-pos) - } - err := encoder.Close() - testEqual(t, "Close gave error %v, want %v", err, error(nil)) - testEqual(t, "Encoding/%d of %q = %q, want %q", bs, gitBigtest.decoded, bb.String(), gitBigtest.encoded) - } -} - -func TestDecode(t *testing.T) { - for _, p := range gitPairs { - dbuf := make([]byte, 4*len(p.encoded)) - ndst, err := Decode(dbuf, []byte(p.encoded)) - testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil)) - testEqual(t, "Decode(%q) = ndst %v, want %v", p.encoded, ndst, len(p.decoded)) - testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:ndst]), p.decoded) - } -} - -func TestDecoder(t *testing.T) { - for _, p := range gitPairs { - decoder := NewDecoder(bytes.NewBufferString(p.encoded)) - dbuf, err := ioutil.ReadAll(decoder) - if err != nil { - t.Fatal("Read failed", err) - } - testEqual(t, "Read from %q = length %v, want %v", p.encoded, len(dbuf), len(p.decoded)) - testEqual(t, "Decoding of %q = %q, want %q", p.encoded, string(dbuf), p.decoded) - if err != nil { - testEqual(t, "Read from %q = %v, want %v", p.encoded, err, io.EOF) - } - } -} - -func TestDecoderBuffering(t *testing.T) { - for bs := 1; bs <= 12; bs++ { - decoder := NewDecoder(bytes.NewBufferString(gitBigtest.encoded)) - buf := make([]byte, len(gitBigtest.decoded)+12) - var total int - for total = 0; total < len(gitBigtest.decoded); { - n, err := decoder.Read(buf[total : total+bs]) - testEqual(t, "Read from %q at pos %d = %d, %v, want _, %v", gitBigtest.encoded, total, n, err, error(nil)) - total += n - } - testEqual(t, "Decoding/%d of %q = %q, want %q", bs, gitBigtest.encoded, string(buf[0:total]), gitBigtest.decoded) - } -} - -func TestDecodeCorrupt(t *testing.T) { - type corrupt struct { - e string - p int - } - examples := []corrupt{ - {"v", 0}, - {"!z!!!!!!!!!", 0}, - } - - for _, e := range examples { - dbuf := make([]byte, 2*len(e.e)) - _, err := Decode(dbuf, []byte(e.e)) - switch err := err.(type) { - case CorruptInputError: - testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p) - default: - t.Error("Decoder failed to detect corruption in", e) - } - } -} - -func TestGitBig(t *testing.T) { - n := 3*1000 + 1 - raw := make([]byte, n) - const alpha = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - for i := 0; i < n; i++ { - raw[i] = alpha[i%len(alpha)] - } - encoded := new(bytes.Buffer) - w := NewEncoder(encoded) - nn, err := w.Write(raw) - if nn != n || err != nil { - t.Fatalf("Encoder.Write(raw) = %d, %v want %d, nil", nn, err, n) - } - err = w.Close() - if err != nil { - t.Fatalf("Encoder.Close() = %v want nil", err) - } - decoded, err := ioutil.ReadAll(NewDecoder(encoded)) - if err != nil { - t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err) - } - - if !bytes.Equal(raw, decoded) { - var i int - for i = 0; i < len(decoded) && i < len(raw); i++ { - if decoded[i] != raw[i] { - break - } - } - t.Errorf("Decode(Encode(%d-byte string)) failed at offset %d", n, i) - } -} diff --git a/libgo/go/encoding/gob/debug.go b/libgo/go/encoding/gob/debug.go index 4a61d0f..6dc7fc9 100644 --- a/libgo/go/encoding/gob/debug.go +++ b/libgo/go/encoding/gob/debug.go @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Delete the next line to include this file in the gob package. +// +build ignore + package gob // This file is not normally included in the gob package. Used only for debugging the package itself. diff --git a/libgo/go/encoding/gob/decoder.go b/libgo/go/encoding/gob/decoder.go index 5e684d3..fb28c8c 100644 --- a/libgo/go/encoding/gob/decoder.go +++ b/libgo/go/encoding/gob/decoder.go @@ -75,7 +75,9 @@ func (dec *Decoder) recvMessage() bool { dec.err = err return false } - if nbytes >= 1<<31 { + // Upper limit of 1GB, allowing room to grow a little without overflow. + // TODO: We might want more control over this limit. + if nbytes >= 1<<30 { dec.err = errBadCount return false } diff --git a/libgo/go/encoding/gob/gobencdec_test.go b/libgo/go/encoding/gob/gobencdec_test.go index b8dfeeb..83644c0 100644 --- a/libgo/go/encoding/gob/gobencdec_test.go +++ b/libgo/go/encoding/gob/gobencdec_test.go @@ -547,7 +547,6 @@ func (a isZeroBugArray) GobEncode() (b []byte, e error) { } func (a *isZeroBugArray) GobDecode(data []byte) error { - println("DECODE") if len(data) != len(a) { return io.EOF } diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index d25ee30..7a05a1b 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -15,26 +15,13 @@ import ( ) const ( - // A generic XML header suitable for use with the output of Marshal and - // MarshalIndent. This is not automatically added to any output of this - // package, it is provided as a convenience. + // A generic XML header suitable for use with the output of Marshal. + // This is not automatically added to any output of this package, + // it is provided as a convenience. Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n" ) -// A Marshaler can produce well-formatted XML representing its internal state. -// It is used by both Marshal and MarshalIndent. -type Marshaler interface { - MarshalXML() ([]byte, error) -} - -type printer struct { - *bufio.Writer -} - -// Marshal writes an XML-formatted representation of v to w. -// -// If v implements Marshaler, then Marshal calls its MarshalXML method. -// Otherwise, Marshal uses the following procedure to create the XML. +// Marshal returns the XML encoding of v. // // 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 @@ -53,6 +40,7 @@ type printer struct { // The XML element for a struct contains marshalled elements for each of the // exported fields of the struct, with these exceptions: // - the XMLName field, described above, is omitted. +// - a field with tag "-" is omitted. // - a field with tag "name,attr" becomes an attribute with // the given name in the XML element. // - a field with tag ",attr" becomes an attribute with the @@ -77,7 +65,7 @@ type printer struct { // Age int `xml:"person>age"` // } // -// xml.Marshal(w, &Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) +// xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) // // would be marshalled as: // @@ -92,13 +80,38 @@ type printer struct { // </result> // // Marshal will return an error if asked to marshal a channel, function, or map. -func Marshal(w io.Writer, v interface{}) (err error) { - p := &printer{bufio.NewWriter(w)} - err = p.marshalValue(reflect.ValueOf(v), nil) - p.Flush() +func Marshal(v interface{}) ([]byte, error) { + var b bytes.Buffer + if err := NewEncoder(&b).Encode(v); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +// An Encoder writes XML data to an output stream. +type Encoder struct { + printer +} + +// NewEncoder returns a new encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{printer{bufio.NewWriter(w)}} +} + +// Encode writes the XML encoding of v to the stream. +// +// See the documentation for Marshal for details about the conversion +// of Go values to XML. +func (enc *Encoder) Encode(v interface{}) error { + err := enc.marshalValue(reflect.ValueOf(v), nil) + enc.Flush() return err } +type printer struct { + *bufio.Writer +} + func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { if !val.IsValid() { return nil @@ -107,18 +120,6 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { kind := val.Kind() typ := val.Type() - // Try Marshaler - if typ.NumMethod() > 0 { - if marshaler, ok := val.Interface().(Marshaler); ok { - bytes, err := marshaler.MarshalXML() - if err != nil { - return err - } - p.Write(bytes) - return nil - } - } - // Drill into pointers/interfaces if kind == reflect.Ptr || kind == reflect.Interface { if val.IsNil() { @@ -181,23 +182,43 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { if finfo.flags&fAttr == 0 { continue } - var str string - if fv := val.FieldByIndex(finfo.idx); fv.Kind() == reflect.String { - str = fv.String() - } else { - str = fmt.Sprint(fv.Interface()) + fv := val.FieldByIndex(finfo.idx) + switch fv.Kind() { + case reflect.String, reflect.Array, reflect.Slice: + // TODO: Should we really do this once ,omitempty is in? + if fv.Len() == 0 { + continue + } } - if str != "" { - p.WriteByte(' ') - p.WriteString(finfo.name) - p.WriteString(`="`) - Escape(p, []byte(str)) - p.WriteByte('"') + p.WriteByte(' ') + p.WriteString(finfo.name) + p.WriteString(`="`) + if err := p.marshalSimple(fv.Type(), fv); err != nil { + return err } + p.WriteByte('"') } p.WriteByte('>') - switch k := val.Kind(); k { + if val.Kind() == reflect.Struct { + err = p.marshalStruct(tinfo, val) + } else { + err = p.marshalSimple(typ, val) + } + if err != nil { + return err + } + + p.WriteByte('<') + p.WriteByte('/') + p.WriteString(name) + p.WriteByte('>') + + return nil +} + +func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) error { + switch val.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: p.WriteString(strconv.FormatInt(val.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: @@ -205,6 +226,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { case reflect.Float32, reflect.Float64: p.WriteString(strconv.FormatFloat(val.Float(), 'g', -1, 64)) case reflect.String: + // TODO: Add EscapeString. Escape(p, []byte(val.String())) case reflect.Bool: p.WriteString(strconv.FormatBool(val.Bool())) @@ -217,21 +239,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { Escape(p, bytes) case reflect.Slice: // will be []byte - bytes := val.Interface().([]byte) - Escape(p, bytes) - case reflect.Struct: - if err := p.marshalStruct(tinfo, val); err != nil { - return err - } + Escape(p, val.Bytes()) default: return &UnsupportedTypeError{typ} } - - p.WriteByte('<') - p.WriteByte('/') - p.WriteString(name) - p.WriteByte('>') - return nil } @@ -358,7 +369,7 @@ func (s *parentStack) push(parents []string) { s.stack = append(s.stack, parents...) } -// A MarshalXMLError is returned when Marshal or MarshalIndent encounter a type +// A MarshalXMLError is returned when Marshal encounters a type // that cannot be converted into XML. type UnsupportedTypeError struct { Type reflect.Type diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index f23b2cb..e0be3320 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -5,7 +5,6 @@ package xml import ( - "bytes" "reflect" "strconv" "strings" @@ -35,12 +34,6 @@ type Ship struct { secret string } -type RawXML string - -func (rx RawXML) MarshalXML() ([]byte, error) { - return []byte(rx), nil -} - type NamedType string type Port struct { @@ -184,6 +177,22 @@ type RecurseB struct { B string } +type PresenceTest struct { + Exists *struct{} +} + +type IgnoreTest struct { + PublicSecret string `xml:"-"` +} + +type MyBytes []byte + +type Data struct { + Bytes []byte + Attr []byte `xml:",attr"` + Custom MyBytes +} + type Plain struct { V interface{} } @@ -225,6 +234,44 @@ var marshalTests = []struct { {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, + // A pointer to struct{} may be used to test for an element's presence. + { + Value: &PresenceTest{new(struct{})}, + ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`, + }, + { + Value: &PresenceTest{}, + ExpectXML: `<PresenceTest></PresenceTest>`, + }, + + // A pointer to struct{} may be used to test for an element's presence. + { + Value: &PresenceTest{new(struct{})}, + ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`, + }, + { + Value: &PresenceTest{}, + ExpectXML: `<PresenceTest></PresenceTest>`, + }, + + // A []byte field is only nil if the element was not found. + { + Value: &Data{}, + ExpectXML: `<Data></Data>`, + UnmarshalOnly: true, + }, + { + Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}}, + ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`, + UnmarshalOnly: true, + }, + + // Check that []byte works, including named []byte types. + { + Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}}, + ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`, + }, + // Test innerxml { Value: &SecretAgent{ @@ -245,13 +292,6 @@ var marshalTests = []struct { UnmarshalOnly: true, }, - // Test marshaller interface - { - Value: RawXML("</>"), - ExpectXML: `</>`, - MarshalOnly: true, - }, - // Test structs {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`}, {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`}, @@ -542,6 +582,22 @@ var marshalTests = []struct { }, ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`, }, + + // Test ignoring fields via "-" tag + { + ExpectXML: `<IgnoreTest></IgnoreTest>`, + Value: &IgnoreTest{}, + }, + { + ExpectXML: `<IgnoreTest></IgnoreTest>`, + Value: &IgnoreTest{PublicSecret: "can't tell"}, + MarshalOnly: true, + }, + { + ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`, + Value: &IgnoreTest{}, + UnmarshalOnly: true, + }, } func TestMarshal(t *testing.T) { @@ -549,13 +605,12 @@ func TestMarshal(t *testing.T) { if test.UnmarshalOnly { continue } - buf := bytes.NewBuffer(nil) - err := Marshal(buf, test.Value) + data, err := Marshal(test.Value) if err != nil { t.Errorf("#%d: Error: %s", idx, err) continue } - if got, want := buf.String(), test.ExpectXML; got != want { + if got, want := string(data), test.ExpectXML; got != want { if strings.Contains(want, "\n") { t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want) } else { @@ -596,8 +651,7 @@ var marshalErrorTests = []struct { func TestMarshalErrors(t *testing.T) { for idx, test := range marshalErrorTests { - buf := bytes.NewBuffer(nil) - err := Marshal(buf, test.Value) + _, err := Marshal(test.Value) if err == nil || err.Error() != test.Err { t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err) } @@ -621,8 +675,7 @@ func TestUnmarshal(t *testing.T) { vt := reflect.TypeOf(test.Value) dest := reflect.New(vt.Elem()).Interface() - buffer := bytes.NewBufferString(test.ExpectXML) - err := Unmarshal(buffer, dest) + err := Unmarshal([]byte(test.ExpectXML), dest) switch fix := dest.(type) { case *Feed: @@ -641,17 +694,14 @@ func TestUnmarshal(t *testing.T) { } func BenchmarkMarshal(b *testing.B) { - buf := bytes.NewBuffer(nil) for i := 0; i < b.N; i++ { - Marshal(buf, atomValue) - buf.Truncate(0) + Marshal(atomValue) } } func BenchmarkUnmarshal(b *testing.B) { xml := []byte(atomXml) for i := 0; i < b.N; i++ { - buffer := bytes.NewBuffer(xml) - Unmarshal(buffer, &Feed{}) + Unmarshal(xml, &Feed{}) } } diff --git a/libgo/go/encoding/xml/read.go b/libgo/go/encoding/xml/read.go index 4419ed1..871fe05 100644 --- a/libgo/go/encoding/xml/read.go +++ b/libgo/go/encoding/xml/read.go @@ -7,7 +7,6 @@ package xml import ( "bytes" "errors" - "io" "reflect" "strconv" "strings" @@ -20,10 +19,10 @@ import ( // See package json for a textual representation more suitable // to data structures. -// Unmarshal parses an XML element from r and uses the -// reflect library to fill in an arbitrary struct, slice, or string -// pointed at by val. Well-formed data that does not fit -// into val is discarded. +// Unmarshal parses the XML-encoded data and stores the result in +// the value pointed to by v, which must be an arbitrary struct, +// slice, or string. Well-formed data that does not fit into v is +// discarded. // // For example, given these definitions: // @@ -59,7 +58,7 @@ import ( // <address>123 Main Street</address> // </result> // -// via Unmarshal(r, &result) is equivalent to assigning +// via Unmarshal(data, &result) is equivalent to assigning // // r = Result{ // xml.Name{Local: "result"}, @@ -78,8 +77,9 @@ import ( // field tag. // // Because Unmarshal uses the reflect package, it can only assign -// to exported (upper case) fields. Unmarshal uses a case-insensitive -// comparison to match XML element names to struct field names. +// to exported (upper case) fields. Unmarshal uses a case-sensitive +// comparison to match XML element names to tag values and struct +// field names. // // Unmarshal maps an XML element to a struct using the following rules. // In the rules, the tag of a field refers to the value associated with the @@ -132,9 +132,11 @@ import ( // of the above rules and the struct has a field with tag ",any", // unmarshal maps the sub-element to that struct field. // +// * A struct field with tag "-" is never unmarshalled into. +// // Unmarshal maps an XML element to a string or []byte by saving the // concatenation of that element's character data in the string or -// []byte. +// []byte. The saved []byte is never nil. // // Unmarshal maps an attribute value to a string or []byte by saving // the value in the string or slice. @@ -156,18 +158,26 @@ import ( // 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. // -func Unmarshal(r io.Reader, val interface{}) error { - v := reflect.ValueOf(val) - if v.Kind() != reflect.Ptr { +func Unmarshal(data []byte, v interface{}) error { + return NewDecoder(bytes.NewBuffer(data)).Decode(v) +} + +// Decode works like xml.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 +// 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. +func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { + val := reflect.ValueOf(v) + if val.Kind() != reflect.Ptr { return errors.New("non-pointer passed to Unmarshal") } - p := NewParser(r) - elem := v.Elem() - err := p.unmarshal(elem, nil) - if err != nil { - return err - } - return nil + return d.unmarshal(val.Elem(), start) } // An UnmarshalError represents an error in the unmarshalling process. @@ -175,22 +185,8 @@ type UnmarshalError string func (e UnmarshalError) Error() string { return string(e) } -// The Parser's Unmarshal method is like xml.Unmarshal -// except that it can be passed a pointer to the initial start element, -// useful when a client reads some raw XML tokens itself -// but also defers to Unmarshal for some elements. -// Passing a nil start element indicates that Unmarshal should -// read the token stream to find the start element. -func (p *Parser) Unmarshal(val interface{}, start *StartElement) error { - v := reflect.ValueOf(val) - if v.Kind() != reflect.Ptr { - return errors.New("non-pointer passed to Unmarshal") - } - return p.unmarshal(v.Elem(), start) -} - // Unmarshal a single XML element into val. -func (p *Parser) unmarshal(val reflect.Value, start *StartElement) error { +func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { // Find start element if we need it. if start == nil { for { @@ -309,14 +305,12 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) error { case fAttr: strv := sv.FieldByIndex(finfo.idx) // Look for attribute. - val := "" for _, a := range start.Attr { if a.Name.Local == finfo.name { - val = a.Value + copyValue(strv, []byte(a.Value)) break } } - copyValue(strv, []byte(val)) case fCharData: if !saveData.IsValid() { @@ -473,7 +467,11 @@ func copyValue(dst reflect.Value, src []byte) (err error) { case reflect.String: t.SetString(string(src)) case reflect.Slice: - t.Set(reflect.ValueOf(src)) + if len(src) == 0 { + // non-nil to flag presence + src = []byte{} + } + t.SetBytes(src) } return nil } @@ -481,9 +479,9 @@ func copyValue(dst reflect.Value, src []byte) (err error) { // unmarshalPath walks down an XML structure looking for wanted // paths, and calls unmarshal on them. // The consumed result tells whether XML elements have been consumed -// from the Parser until start's matching end element, or if it's +// from the Decoder until start's matching end element, or if it's // still untouched because start is uninteresting for sv's fields. -func (p *Parser) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { +func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) { recurse := false Loop: for i := range tinfo.fields { @@ -547,7 +545,7 @@ Loop: // Read tokens until we find the end element. // Token is taking care of making sure the // end element matches the start element we saw. -func (p *Parser) Skip() error { +func (p *Decoder) Skip() error { for { tok, err := p.Token() if err != nil { diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go index ff61bd7..833eafc 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -6,7 +6,6 @@ package xml import ( "reflect" - "strings" "testing" ) @@ -14,7 +13,7 @@ import ( func TestUnmarshalFeed(t *testing.T) { var f Feed - if err := Unmarshal(strings.NewReader(atomFeedString), &f); err != nil { + if err := Unmarshal([]byte(atomFeedString), &f); err != nil { t.Fatalf("Unmarshal: %s", err) } if !reflect.DeepEqual(f, atomFeed) { @@ -281,7 +280,7 @@ var pathTests = []interface{}{ func TestUnmarshalPaths(t *testing.T) { for _, pt := range pathTests { v := reflect.New(reflect.TypeOf(pt).Elem()).Interface() - if err := Unmarshal(strings.NewReader(pathTestString), v); err != nil { + if err := Unmarshal([]byte(pathTestString), v); err != nil { t.Fatalf("Unmarshal: %s", err) } if !reflect.DeepEqual(v, pt) { @@ -331,7 +330,7 @@ var badPathTests = []struct { func TestUnmarshalBadPaths(t *testing.T) { for _, tt := range badPathTests { - err := Unmarshal(strings.NewReader(pathTestString), tt.v) + err := Unmarshal([]byte(pathTestString), tt.v) if !reflect.DeepEqual(err, tt.e) { t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e) } @@ -350,7 +349,7 @@ type TestThree struct { func TestUnmarshalWithoutNameType(t *testing.T) { var x TestThree - if err := Unmarshal(strings.NewReader(withoutNameTypeData), &x); err != nil { + if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil { t.Fatalf("Unmarshal: %s", err) } if x.Attr != OK { diff --git a/libgo/go/encoding/xml/typeinfo.go b/libgo/go/encoding/xml/typeinfo.go index 36b35ed..2bf2c6b 100644 --- a/libgo/go/encoding/xml/typeinfo.go +++ b/libgo/go/encoding/xml/typeinfo.go @@ -37,7 +37,6 @@ const ( fAny // TODO: - //fIgnore //fOmitEmpty fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny @@ -62,7 +61,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) { n := typ.NumField() for i := 0; i < n; i++ { f := typ.Field(i) - if f.PkgPath != "" { + if f.PkgPath != "" || f.Tag.Get("xml") == "-" { continue // Private field } diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index d001c40..5066f5c 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -36,7 +36,7 @@ func (e *SyntaxError) Error() string { // A Name represents an XML name (Local) annotated // with a name space identifier (Space). -// In tokens returned by Parser.Token, the Space identifier +// In tokens returned by Decoder.Token, the Space identifier // is given as a canonical URL, not the short prefix used // in the document being parsed. type Name struct { @@ -124,9 +124,9 @@ func CopyToken(t Token) Token { return t } -// A Parser represents an XML parser reading a particular input stream. +// A Decoder represents an XML parser reading a particular input stream. // The parser assumes that its input is encoded in UTF-8. -type Parser struct { +type Decoder struct { // Strict defaults to true, enforcing the requirements // of the XML specification. // If set to false, the parser allows input containing common @@ -139,9 +139,9 @@ type Parser struct { // // Setting: // - // p.Strict = false; - // p.AutoClose = HTMLAutoClose; - // p.Entity = HTMLEntity + // d.Strict = false; + // d.AutoClose = HTMLAutoClose; + // d.Entity = HTMLEntity // // creates a parser that can handle typical HTML. Strict bool @@ -184,16 +184,16 @@ type Parser struct { tmp [32]byte } -// NewParser creates a new XML parser reading from r. -func NewParser(r io.Reader) *Parser { - p := &Parser{ +// NewDecoder creates a new XML parser reading from r. +func NewDecoder(r io.Reader) *Decoder { + d := &Decoder{ ns: make(map[string]string), nextByte: -1, line: 1, Strict: true, } - p.switchToReader(r) - return p + d.switchToReader(r) + return d } // Token returns the next XML token in the input stream. @@ -218,17 +218,17 @@ func NewParser(r io.Reader) *Parser { // 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 (p *Parser) Token() (t Token, err error) { - if p.nextToken != nil { - t = p.nextToken - p.nextToken = nil - } else if t, err = p.RawToken(); err != nil { +func (d *Decoder) Token() (t Token, err error) { + if d.nextToken != nil { + t = d.nextToken + d.nextToken = nil + } else if t, err = d.RawToken(); err != nil { return } - if !p.Strict { - if t1, ok := p.autoClose(t); ok { - p.nextToken = t + if !d.Strict { + if t1, ok := d.autoClose(t); ok { + d.nextToken = t t = t1 } } @@ -240,29 +240,29 @@ func (p *Parser) Token() (t Token, err error) { // the translations first. for _, a := range t1.Attr { if a.Name.Space == "xmlns" { - v, ok := p.ns[a.Name.Local] - p.pushNs(a.Name.Local, v, ok) - p.ns[a.Name.Local] = a.Value + v, ok := d.ns[a.Name.Local] + d.pushNs(a.Name.Local, v, ok) + d.ns[a.Name.Local] = a.Value } if a.Name.Space == "" && a.Name.Local == "xmlns" { // Default space for untagged names - v, ok := p.ns[""] - p.pushNs("", v, ok) - p.ns[""] = a.Value + v, ok := d.ns[""] + d.pushNs("", v, ok) + d.ns[""] = a.Value } } - p.translate(&t1.Name, true) + d.translate(&t1.Name, true) for i := range t1.Attr { - p.translate(&t1.Attr[i].Name, false) + d.translate(&t1.Attr[i].Name, false) } - p.pushElement(t1.Name) + d.pushElement(t1.Name) t = t1 case EndElement: - p.translate(&t1.Name, true) - if !p.popElement(&t1) { - return nil, p.err + d.translate(&t1.Name, true) + if !d.popElement(&t1) { + return nil, d.err } t = t1 } @@ -272,7 +272,7 @@ func (p *Parser) Token() (t Token, err error) { // Apply name space translation to name n. // The default name space (for Space=="") // applies only to element names, not to attribute names. -func (p *Parser) translate(n *Name, isElementName bool) { +func (d *Decoder) translate(n *Name, isElementName bool) { switch { case n.Space == "xmlns": return @@ -281,20 +281,20 @@ func (p *Parser) translate(n *Name, isElementName bool) { case n.Space == "" && n.Local == "xmlns": return } - if v, ok := p.ns[n.Space]; ok { + if v, ok := d.ns[n.Space]; ok { n.Space = v } } -func (p *Parser) switchToReader(r io.Reader) { +func (d *Decoder) switchToReader(r io.Reader) { // Get efficient byte at a time reader. // Assume that if reader has its own // ReadByte, it's efficient enough. // Otherwise, use bufio. if rb, ok := r.(io.ByteReader); ok { - p.r = rb + d.r = rb } else { - p.r = bufio.NewReader(r) + d.r = bufio.NewReader(r) } } @@ -314,47 +314,47 @@ const ( stkNs ) -func (p *Parser) push(kind int) *stack { - s := p.free +func (d *Decoder) push(kind int) *stack { + s := d.free if s != nil { - p.free = s.next + d.free = s.next } else { s = new(stack) } - s.next = p.stk + s.next = d.stk s.kind = kind - p.stk = s + d.stk = s return s } -func (p *Parser) pop() *stack { - s := p.stk +func (d *Decoder) pop() *stack { + s := d.stk if s != nil { - p.stk = s.next - s.next = p.free - p.free = s + d.stk = s.next + s.next = d.free + d.free = s } return s } // Record that we are starting an element with the given name. -func (p *Parser) pushElement(name Name) { - s := p.push(stkStart) +func (d *Decoder) pushElement(name Name) { + s := d.push(stkStart) s.name = name } // Record that we are changing the value of ns[local]. // The old value is url, ok. -func (p *Parser) pushNs(local string, url string, ok bool) { - s := p.push(stkNs) +func (d *Decoder) pushNs(local string, url string, ok bool) { + s := d.push(stkNs) s.name.Local = local s.name.Space = url s.ok = ok } // Creates a SyntaxError with the current line number. -func (p *Parser) syntaxError(msg string) error { - return &SyntaxError{Msg: msg, Line: p.line} +func (d *Decoder) syntaxError(msg string) error { + return &SyntaxError{Msg: msg, Line: d.line} } // Record that we are ending an element with the given name. @@ -363,36 +363,36 @@ func (p *Parser) syntaxError(msg string) error { // After popping the element, apply any undo records from // the stack to restore the name translations that existed // before we saw this element. -func (p *Parser) popElement(t *EndElement) bool { - s := p.pop() +func (d *Decoder) popElement(t *EndElement) bool { + s := d.pop() name := t.Name switch { case s == nil || s.kind != stkStart: - p.err = p.syntaxError("unexpected end element </" + name.Local + ">") + d.err = d.syntaxError("unexpected end element </" + name.Local + ">") return false case s.name.Local != name.Local: - if !p.Strict { - p.needClose = true - p.toClose = t.Name + if !d.Strict { + d.needClose = true + d.toClose = t.Name t.Name = s.name return true } - p.err = p.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">") + d.err = d.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">") return false case s.name.Space != name.Space: - p.err = p.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + + d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + "closed by </" + name.Local + "> in space " + name.Space) return false } // Pop stack until a Start is on the top, undoing the // translations that were associated with the element we just closed. - for p.stk != nil && p.stk.kind != stkStart { - s := p.pop() + for d.stk != nil && d.stk.kind != stkStart { + s := d.pop() if s.ok { - p.ns[s.name.Local] = s.name.Space + d.ns[s.name.Local] = s.name.Space } else { - delete(p.ns, s.name.Local) + delete(d.ns, s.name.Local) } } @@ -401,17 +401,17 @@ func (p *Parser) popElement(t *EndElement) bool { // If the top element on the stack is autoclosing and // t is not the end tag, invent the end tag. -func (p *Parser) autoClose(t Token) (Token, bool) { - if p.stk == nil || p.stk.kind != stkStart { +func (d *Decoder) autoClose(t Token) (Token, bool) { + if d.stk == nil || d.stk.kind != stkStart { return nil, false } - name := strings.ToLower(p.stk.name.Local) - for _, s := range p.AutoClose { + name := strings.ToLower(d.stk.name.Local) + for _, s := range d.AutoClose { if strings.ToLower(s) == name { // This one should be auto closed if t doesn't close it. et, ok := t.(EndElement) if !ok || et.Name.Local != name { - return EndElement{p.stk.name}, true + return EndElement{d.stk.name}, true } break } @@ -422,53 +422,53 @@ func (p *Parser) autoClose(t Token) (Token, bool) { // RawToken is like Token but does not verify that // start and end elements match and does not translate // name space prefixes to their corresponding URLs. -func (p *Parser) RawToken() (Token, error) { - if p.err != nil { - return nil, p.err +func (d *Decoder) RawToken() (Token, error) { + if d.err != nil { + return nil, d.err } - if p.needClose { + if d.needClose { // The last element we read was self-closing and // we returned just the StartElement half. // Return the EndElement half now. - p.needClose = false - return EndElement{p.toClose}, nil + d.needClose = false + return EndElement{d.toClose}, nil } - b, ok := p.getc() + b, ok := d.getc() if !ok { - return nil, p.err + return nil, d.err } if b != '<' { // Text section. - p.ungetc(b) - data := p.text(-1, false) + d.ungetc(b) + data := d.text(-1, false) if data == nil { - return nil, p.err + return nil, d.err } return CharData(data), nil } - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } switch b { case '/': // </: End element var name Name - if name, ok = p.nsname(); !ok { - if p.err == nil { - p.err = p.syntaxError("expected element name after </") + if name, ok = d.nsname(); !ok { + if d.err == nil { + d.err = d.syntaxError("expected element name after </") } - return nil, p.err + return nil, d.err } - p.space() - if b, ok = p.mustgetc(); !ok { - return nil, p.err + d.space() + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b != '>' { - p.err = p.syntaxError("invalid characters between </" + name.Local + " and >") - return nil, p.err + d.err = d.syntaxError("invalid characters between </" + name.Local + " and >") + return nil, d.err } return EndElement{name}, nil @@ -477,95 +477,95 @@ func (p *Parser) RawToken() (Token, error) { // TODO(rsc): Should parse the <?xml declaration to make sure // the version is 1.0 and the encoding is UTF-8. var target string - if target, ok = p.name(); !ok { - if p.err == nil { - p.err = p.syntaxError("expected target name after <?") + if target, ok = d.name(); !ok { + if d.err == nil { + d.err = d.syntaxError("expected target name after <?") } - return nil, p.err + return nil, d.err } - p.space() - p.buf.Reset() + d.space() + d.buf.Reset() var b0 byte for { - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } - p.buf.WriteByte(b) + d.buf.WriteByte(b) if b0 == '?' && b == '>' { break } b0 = b } - data := p.buf.Bytes() + data := d.buf.Bytes() data = data[0 : len(data)-2] // chop ?> if target == "xml" { enc := procInstEncoding(string(data)) if enc != "" && enc != "utf-8" && enc != "UTF-8" { - if p.CharsetReader == nil { - p.err = fmt.Errorf("xml: encoding %q declared but Parser.CharsetReader is nil", enc) - return nil, p.err + if d.CharsetReader == nil { + d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc) + return nil, d.err } - newr, err := p.CharsetReader(enc, p.r.(io.Reader)) + newr, err := d.CharsetReader(enc, d.r.(io.Reader)) if err != nil { - p.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) - return nil, p.err + d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) + return nil, d.err } if newr == nil { panic("CharsetReader returned a nil Reader for charset " + enc) } - p.switchToReader(newr) + d.switchToReader(newr) } } return ProcInst{target, data}, nil case '!': // <!: Maybe comment, maybe CDATA. - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } switch b { case '-': // <!- // Probably <!-- for a comment. - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b != '-' { - p.err = p.syntaxError("invalid sequence <!- not part of <!--") - return nil, p.err + d.err = d.syntaxError("invalid sequence <!- not part of <!--") + return nil, d.err } // Look for terminator. - p.buf.Reset() + d.buf.Reset() var b0, b1 byte for { - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } - p.buf.WriteByte(b) + d.buf.WriteByte(b) if b0 == '-' && b1 == '-' && b == '>' { break } b0, b1 = b1, b } - data := p.buf.Bytes() + data := d.buf.Bytes() data = data[0 : len(data)-3] // chop --> return Comment(data), nil case '[': // <![ // Probably <![CDATA[. for i := 0; i < 6; i++ { - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b != "CDATA["[i] { - p.err = p.syntaxError("invalid <![ sequence") - return nil, p.err + d.err = d.syntaxError("invalid <![ sequence") + return nil, d.err } } // Have <![CDATA[. Read text until ]]>. - data := p.text(-1, true) + data := d.text(-1, true) if data == nil { - return nil, p.err + return nil, d.err } return CharData(data), nil } @@ -573,18 +573,18 @@ func (p *Parser) RawToken() (Token, error) { // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc. // We don't care, but accumulate for caller. Quoted angle // brackets do not count for nesting. - p.buf.Reset() - p.buf.WriteByte(b) + d.buf.Reset() + d.buf.WriteByte(b) inquote := uint8(0) depth := 0 for { - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if inquote == 0 && b == '>' && depth == 0 { break } - p.buf.WriteByte(b) + d.buf.WriteByte(b) switch { case b == inquote: inquote = 0 @@ -602,45 +602,45 @@ func (p *Parser) RawToken() (Token, error) { depth++ } } - return Directive(p.buf.Bytes()), nil + return Directive(d.buf.Bytes()), nil } // Must be an open element like <a href="foo"> - p.ungetc(b) + d.ungetc(b) var ( name Name empty bool attr []Attr ) - if name, ok = p.nsname(); !ok { - if p.err == nil { - p.err = p.syntaxError("expected element name after <") + if name, ok = d.nsname(); !ok { + if d.err == nil { + d.err = d.syntaxError("expected element name after <") } - return nil, p.err + return nil, d.err } attr = make([]Attr, 0, 4) for { - p.space() - if b, ok = p.mustgetc(); !ok { - return nil, p.err + d.space() + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b == '/' { empty = true - if b, ok = p.mustgetc(); !ok { - return nil, p.err + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b != '>' { - p.err = p.syntaxError("expected /> in element") - return nil, p.err + d.err = d.syntaxError("expected /> in element") + return nil, d.err } break } if b == '>' { break } - p.ungetc(b) + d.ungetc(b) n := len(attr) if n >= cap(attr) { @@ -650,85 +650,85 @@ func (p *Parser) RawToken() (Token, error) { } attr = attr[0 : n+1] a := &attr[n] - if a.Name, ok = p.nsname(); !ok { - if p.err == nil { - p.err = p.syntaxError("expected attribute name in element") + if a.Name, ok = d.nsname(); !ok { + if d.err == nil { + d.err = d.syntaxError("expected attribute name in element") } - return nil, p.err + return nil, d.err } - p.space() - if b, ok = p.mustgetc(); !ok { - return nil, p.err + d.space() + if b, ok = d.mustgetc(); !ok { + return nil, d.err } if b != '=' { - if p.Strict { - p.err = p.syntaxError("attribute name without = in element") - return nil, p.err + if d.Strict { + d.err = d.syntaxError("attribute name without = in element") + return nil, d.err } else { - p.ungetc(b) + d.ungetc(b) a.Value = a.Name.Local } } else { - p.space() - data := p.attrval() + d.space() + data := d.attrval() if data == nil { - return nil, p.err + return nil, d.err } a.Value = string(data) } } if empty { - p.needClose = true - p.toClose = name + d.needClose = true + d.toClose = name } return StartElement{name, attr}, nil } -func (p *Parser) attrval() []byte { - b, ok := p.mustgetc() +func (d *Decoder) attrval() []byte { + b, ok := d.mustgetc() if !ok { return nil } // Handle quoted attribute values if b == '"' || b == '\'' { - return p.text(int(b), false) + return d.text(int(b), false) } // Handle unquoted attribute values for strict parsers - if p.Strict { - p.err = p.syntaxError("unquoted or missing attribute value in element") + if d.Strict { + d.err = d.syntaxError("unquoted or missing attribute value in element") return nil } // Handle unquoted attribute values for unstrict parsers - p.ungetc(b) - p.buf.Reset() + d.ungetc(b) + d.buf.Reset() for { - b, ok = p.mustgetc() + b, ok = d.mustgetc() if !ok { return nil } // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' { - p.buf.WriteByte(b) + d.buf.WriteByte(b) } else { - p.ungetc(b) + d.ungetc(b) break } } - return p.buf.Bytes() + return d.buf.Bytes() } // Skip spaces if any -func (p *Parser) space() { +func (d *Decoder) space() { for { - b, ok := p.getc() + b, ok := d.getc() if !ok { return } switch b { case ' ', '\r', '\n', '\t': default: - p.ungetc(b) + d.ungetc(b) return } } @@ -736,35 +736,35 @@ func (p *Parser) space() { // Read a single byte. // If there is no byte to read, return ok==false -// and leave the error in p.err. +// and leave the error in d.err. // Maintain line number. -func (p *Parser) getc() (b byte, ok bool) { - if p.err != nil { +func (d *Decoder) getc() (b byte, ok bool) { + if d.err != nil { return 0, false } - if p.nextByte >= 0 { - b = byte(p.nextByte) - p.nextByte = -1 + if d.nextByte >= 0 { + b = byte(d.nextByte) + d.nextByte = -1 } else { - b, p.err = p.r.ReadByte() - if p.err != nil { + b, d.err = d.r.ReadByte() + if d.err != nil { return 0, false } - if p.saved != nil { - p.saved.WriteByte(b) + if d.saved != nil { + d.saved.WriteByte(b) } } if b == '\n' { - p.line++ + d.line++ } return b, true } // Return saved offset. // If we did ungetc (nextByte >= 0), have to back up one. -func (p *Parser) savedOffset() int { - n := p.saved.Len() - if p.nextByte >= 0 { +func (d *Decoder) savedOffset() int { + n := d.saved.Len() + if d.nextByte >= 0 { n-- } return n @@ -772,23 +772,23 @@ func (p *Parser) savedOffset() int { // Must read a single byte. // If there is no byte to read, -// set p.err to SyntaxError("unexpected EOF") +// set d.err to SyntaxError("unexpected EOF") // and return ok==false -func (p *Parser) mustgetc() (b byte, ok bool) { - if b, ok = p.getc(); !ok { - if p.err == io.EOF { - p.err = p.syntaxError("unexpected EOF") +func (d *Decoder) mustgetc() (b byte, ok bool) { + if b, ok = d.getc(); !ok { + if d.err == io.EOF { + d.err = d.syntaxError("unexpected EOF") } } return } // Unread a single byte. -func (p *Parser) ungetc(b byte) { +func (d *Decoder) ungetc(b byte) { if b == '\n' { - p.line-- + d.line-- } - p.nextByte = int(b) + d.nextByte = int(b) } var entity = map[string]int{ @@ -802,18 +802,18 @@ var entity = map[string]int{ // Read plain text section (XML calls it character data). // If quote >= 0, we are in a quoted string and need to find the matching quote. // If cdata == true, we are in a <![CDATA[ section and need to find ]]>. -// On failure return nil and leave the error in p.err. -func (p *Parser) text(quote int, cdata bool) []byte { +// On failure return nil and leave the error in d.err. +func (d *Decoder) text(quote int, cdata bool) []byte { var b0, b1 byte var trunc int - p.buf.Reset() + d.buf.Reset() Input: for { - b, ok := p.getc() + b, ok := d.getc() if !ok { if cdata { - if p.err == io.EOF { - p.err = p.syntaxError("unexpected EOF in CDATA section") + if d.err == io.EOF { + d.err = d.syntaxError("unexpected EOF in CDATA section") } return nil } @@ -827,17 +827,17 @@ Input: trunc = 2 break Input } - p.err = p.syntaxError("unescaped ]]> not in CDATA section") + d.err = d.syntaxError("unescaped ]]> not in CDATA section") return nil } // Stop reading text if we see a <. if b == '<' && !cdata { if quote >= 0 { - p.err = p.syntaxError("unescaped < inside quoted string") + d.err = d.syntaxError("unescaped < inside quoted string") return nil } - p.ungetc('<') + d.ungetc('<') break Input } if quote >= 0 && b == byte(quote) { @@ -850,16 +850,16 @@ Input: // Parsers are required to recognize lt, gt, amp, apos, and quot // even if they have not been declared. That's all we allow. var i int - for i = 0; i < len(p.tmp); i++ { + for i = 0; i < len(d.tmp); i++ { var ok bool - p.tmp[i], ok = p.getc() + d.tmp[i], ok = d.getc() if !ok { - if p.err == io.EOF { - p.err = p.syntaxError("unexpected EOF") + if d.err == io.EOF { + d.err = d.syntaxError("unexpected EOF") } return nil } - c := p.tmp[i] + c := d.tmp[i] if c == ';' { break } @@ -869,18 +869,18 @@ Input: c == '_' || c == '#' { continue } - p.ungetc(c) + d.ungetc(c) break } - s := string(p.tmp[0:i]) - if i >= len(p.tmp) { - if !p.Strict { + s := string(d.tmp[0:i]) + if i >= len(d.tmp) { + if !d.Strict { b0, b1 = 0, 0 - p.buf.WriteByte('&') - p.buf.Write(p.tmp[0:i]) + d.buf.WriteByte('&') + d.buf.Write(d.tmp[0:i]) continue Input } - p.err = p.syntaxError("character entity expression &" + s + "... too long") + d.err = d.syntaxError("character entity expression &" + s + "... too long") return nil } var haveText bool @@ -901,28 +901,28 @@ Input: if r, ok := entity[s]; ok { text = string(r) haveText = true - } else if p.Entity != nil { - text, haveText = p.Entity[s] + } else if d.Entity != nil { + text, haveText = d.Entity[s] } } if !haveText { - if !p.Strict { + if !d.Strict { b0, b1 = 0, 0 - p.buf.WriteByte('&') - p.buf.Write(p.tmp[0:i]) + d.buf.WriteByte('&') + d.buf.Write(d.tmp[0:i]) continue Input } - p.err = p.syntaxError("invalid character entity &" + s + ";") + d.err = d.syntaxError("invalid character entity &" + s + ";") return nil } - p.buf.Write([]byte(text)) + d.buf.Write([]byte(text)) b0, b1 = 0, 0 continue Input } - p.buf.WriteByte(b) + d.buf.WriteByte(b) b0, b1 = b1, b } - data := p.buf.Bytes() + data := d.buf.Bytes() data = data[0 : len(data)-trunc] // Inspect each rune for being a disallowed character. @@ -930,12 +930,12 @@ Input: for len(buf) > 0 { r, size := utf8.DecodeRune(buf) if r == utf8.RuneError && size == 1 { - p.err = p.syntaxError("invalid UTF-8") + d.err = d.syntaxError("invalid UTF-8") return nil } buf = buf[size:] if !isInCharacterRange(r) { - p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r)) + d.err = d.syntaxError(fmt.Sprintf("illegal character code %U", r)) return nil } } @@ -970,8 +970,8 @@ func isInCharacterRange(r rune) (inrange bool) { // Get name space name: name with a : stuck in the middle. // The part before the : is the name space identifier. -func (p *Parser) nsname() (name Name, ok bool) { - s, ok := p.name() +func (d *Decoder) nsname() (name Name, ok bool) { + s, ok := d.name() if !ok { return } @@ -986,37 +986,37 @@ func (p *Parser) nsname() (name Name, ok bool) { } // Get name: /first(first|second)*/ -// Do not set p.err if the name is missing (unless unexpected EOF is received): +// Do not set d.err if the name is missing (unless unexpected EOF is received): // let the caller provide better context. -func (p *Parser) name() (s string, ok bool) { +func (d *Decoder) name() (s string, ok bool) { var b byte - if b, ok = p.mustgetc(); !ok { + if b, ok = d.mustgetc(); !ok { return } // As a first approximation, we gather the bytes [A-Za-z_:.-\x80-\xFF]* if b < utf8.RuneSelf && !isNameByte(b) { - p.ungetc(b) + d.ungetc(b) return "", false } - p.buf.Reset() - p.buf.WriteByte(b) + d.buf.Reset() + d.buf.WriteByte(b) for { - if b, ok = p.mustgetc(); !ok { + if b, ok = d.mustgetc(); !ok { return } if b < utf8.RuneSelf && !isNameByte(b) { - p.ungetc(b) + d.ungetc(b) break } - p.buf.WriteByte(b) + d.buf.WriteByte(b) } // Then we check the characters. - s = p.buf.String() + s = d.buf.String() for i, c := range s { if !unicode.Is(first, c) && (i == 0 || !unicode.Is(second, c)) { - p.err = p.syntaxError("invalid XML name: " + s) + d.err = d.syntaxError("invalid XML name: " + s) return "", false } } diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index 524d4dda..1d0696c 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -5,7 +5,6 @@ package xml import ( - "bytes" "io" "reflect" "strings" @@ -155,8 +154,8 @@ var xmlInput = []string{ } func TestRawToken(t *testing.T) { - p := NewParser(strings.NewReader(testInput)) - testRawToken(t, p, rawTokens) + d := NewDecoder(strings.NewReader(testInput)) + testRawToken(t, d, rawTokens) } type downCaser struct { @@ -179,27 +178,27 @@ func (d *downCaser) Read(p []byte) (int, error) { func TestRawTokenAltEncoding(t *testing.T) { sawEncoding := "" - p := NewParser(strings.NewReader(testInputAltEncoding)) - p.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { + d := NewDecoder(strings.NewReader(testInputAltEncoding)) + d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { sawEncoding = charset if charset != "x-testing-uppercase" { t.Fatalf("unexpected charset %q", charset) } return &downCaser{t, input.(io.ByteReader)}, nil } - testRawToken(t, p, rawTokensAltEncoding) + testRawToken(t, d, rawTokensAltEncoding) } func TestRawTokenAltEncodingNoConverter(t *testing.T) { - p := NewParser(strings.NewReader(testInputAltEncoding)) - token, err := p.RawToken() + d := NewDecoder(strings.NewReader(testInputAltEncoding)) + token, err := d.RawToken() if token == nil { t.Fatalf("expected a token on first RawToken call") } if err != nil { t.Fatal(err) } - token, err = p.RawToken() + token, err = d.RawToken() if token != nil { t.Errorf("expected a nil token; got %#v", token) } @@ -213,9 +212,9 @@ func TestRawTokenAltEncodingNoConverter(t *testing.T) { } } -func testRawToken(t *testing.T, p *Parser, rawTokens []Token) { +func testRawToken(t *testing.T, d *Decoder, rawTokens []Token) { for i, want := range rawTokens { - have, err := p.RawToken() + have, err := d.RawToken() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } @@ -258,10 +257,10 @@ var nestedDirectivesTokens = []Token{ } func TestNestedDirectives(t *testing.T) { - p := NewParser(strings.NewReader(nestedDirectivesInput)) + d := NewDecoder(strings.NewReader(nestedDirectivesInput)) for i, want := range nestedDirectivesTokens { - have, err := p.Token() + have, err := d.Token() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } @@ -272,10 +271,10 @@ func TestNestedDirectives(t *testing.T) { } func TestToken(t *testing.T) { - p := NewParser(strings.NewReader(testInput)) + d := NewDecoder(strings.NewReader(testInput)) for i, want := range cookedTokens { - have, err := p.Token() + have, err := d.Token() if err != nil { t.Fatalf("token %d: unexpected error: %s", i, err) } @@ -287,9 +286,9 @@ func TestToken(t *testing.T) { func TestSyntax(t *testing.T) { for i := range xmlInput { - p := NewParser(strings.NewReader(xmlInput[i])) + d := NewDecoder(strings.NewReader(xmlInput[i])) var err error - for _, err = p.Token(); err == nil; _, err = p.Token() { + for _, err = d.Token(); err == nil; _, err = d.Token() { } if _, ok := err.(*SyntaxError); !ok { t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i]) @@ -368,8 +367,7 @@ const testScalarsInput = `<allscalars> func TestAllScalars(t *testing.T) { var a allScalars - buf := bytes.NewBufferString(testScalarsInput) - err := Unmarshal(buf, &a) + err := Unmarshal([]byte(testScalarsInput), &a) if err != nil { t.Fatal(err) @@ -386,8 +384,7 @@ type item struct { func TestIssue569(t *testing.T) { data := `<item><Field_a>abcd</Field_a></item>` var i item - buf := bytes.NewBufferString(data) - err := Unmarshal(buf, &i) + err := Unmarshal([]byte(data), &i) if err != nil || i.Field_a != "abcd" { t.Fatal("Expecting abcd") @@ -396,9 +393,9 @@ func TestIssue569(t *testing.T) { func TestUnquotedAttrs(t *testing.T) { data := "<tag attr=azAZ09:-_\t>" - p := NewParser(strings.NewReader(data)) - p.Strict = false - token, err := p.Token() + d := NewDecoder(strings.NewReader(data)) + d.Strict = false + token, err := d.Token() if _, ok := err.(*SyntaxError); ok { t.Errorf("Unexpected error: %v", err) } @@ -422,9 +419,9 @@ func TestValuelessAttrs(t *testing.T) { {"<input checked />", "input", "checked"}, } for _, test := range tests { - p := NewParser(strings.NewReader(test[0])) - p.Strict = false - token, err := p.Token() + d := NewDecoder(strings.NewReader(test[0])) + d.Strict = false + token, err := d.Token() if _, ok := err.(*SyntaxError); ok { t.Errorf("Unexpected error: %v", err) } @@ -472,9 +469,9 @@ func TestCopyTokenStartElement(t *testing.T) { func TestSyntaxErrorLineNum(t *testing.T) { testInput := "<P>Foo<P>\n\n<P>Bar</>\n" - p := NewParser(strings.NewReader(testInput)) + d := NewDecoder(strings.NewReader(testInput)) var err error - for _, err = p.Token(); err == nil; _, err = p.Token() { + for _, err = d.Token(); err == nil; _, err = d.Token() { } synerr, ok := err.(*SyntaxError) if !ok { @@ -487,41 +484,41 @@ func TestSyntaxErrorLineNum(t *testing.T) { func TestTrailingRawToken(t *testing.T) { input := `<FOO></FOO> ` - p := NewParser(strings.NewReader(input)) + d := NewDecoder(strings.NewReader(input)) var err error - for _, err = p.RawToken(); err == nil; _, err = p.RawToken() { + for _, err = d.RawToken(); err == nil; _, err = d.RawToken() { } if err != io.EOF { - t.Fatalf("p.RawToken() = _, %v, want _, io.EOF", err) + t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err) } } func TestTrailingToken(t *testing.T) { input := `<FOO></FOO> ` - p := NewParser(strings.NewReader(input)) + d := NewDecoder(strings.NewReader(input)) var err error - for _, err = p.Token(); err == nil; _, err = p.Token() { + for _, err = d.Token(); err == nil; _, err = d.Token() { } if err != io.EOF { - t.Fatalf("p.Token() = _, %v, want _, io.EOF", err) + t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) } } func TestEntityInsideCDATA(t *testing.T) { input := `<test><![CDATA[ &val=foo ]]></test>` - p := NewParser(strings.NewReader(input)) + d := NewDecoder(strings.NewReader(input)) var err error - for _, err = p.Token(); err == nil; _, err = p.Token() { + for _, err = d.Token(); err == nil; _, err = d.Token() { } if err != io.EOF { - t.Fatalf("p.Token() = _, %v, want _, io.EOF", err) + t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) } } // The last three tests (respectively one for characters in attribute // names and two for character entities) pass not because of code // changed for issue 1259, but instead pass with the given messages -// from other parts of xml.Parser. I provide these to note the +// from other parts of xml.Decoder. I provide these to note the // current behavior of situations where one might think that character // range checking would detect the error, but it does not in fact. @@ -541,15 +538,15 @@ var characterTests = []struct { func TestDisallowedCharacters(t *testing.T) { for i, tt := range characterTests { - p := NewParser(strings.NewReader(tt.in)) + d := NewDecoder(strings.NewReader(tt.in)) var err error for err == nil { - _, err = p.Token() + _, err = d.Token() } synerr, ok := err.(*SyntaxError) if !ok { - t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err) + t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err) } if synerr.Msg != tt.err { t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg) |