aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/encoding')
-rw-r--r--libgo/go/encoding/binary/varint.go19
-rw-r--r--libgo/go/encoding/binary/varint_test.go32
-rw-r--r--libgo/go/encoding/git85/git.go276
-rw-r--r--libgo/go/encoding/git85/git_test.go194
-rw-r--r--libgo/go/encoding/gob/debug.go3
-rw-r--r--libgo/go/encoding/gob/decoder.go4
-rw-r--r--libgo/go/encoding/gob/gobencdec_test.go1
-rw-r--r--libgo/go/encoding/xml/marshal.go129
-rw-r--r--libgo/go/encoding/xml/marshal_test.go102
-rw-r--r--libgo/go/encoding/xml/read.go80
-rw-r--r--libgo/go/encoding/xml/read_test.go9
-rw-r--r--libgo/go/encoding/xml/typeinfo.go3
-rw-r--r--libgo/go/encoding/xml/xml.go482
-rw-r--r--libgo/go/encoding/xml/xml_test.go81
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)