aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/xml
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-05-20 00:18:15 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-05-20 00:18:15 +0000
commit9ff56c9570642711d5b7ab29920ecf5dbff14a27 (patch)
treec891bdec1e6f073f73fedeef23718bc3ac30d499 /libgo/go/xml
parent37cb25ed7acdb844b218231130e54b8b7a0ff6e6 (diff)
downloadgcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.zip
gcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.tar.gz
gcc-9ff56c9570642711d5b7ab29920ecf5dbff14a27.tar.bz2
Update to current version of Go library.
From-SVN: r173931
Diffstat (limited to 'libgo/go/xml')
-rw-r--r--libgo/go/xml/read.go119
-rw-r--r--libgo/go/xml/read_test.go8
-rw-r--r--libgo/go/xml/xml.go73
-rw-r--r--libgo/go/xml/xml_test.go173
4 files changed, 259 insertions, 114 deletions
diff --git a/libgo/go/xml/read.go b/libgo/go/xml/read.go
index 9ae3bb8..e2b349c 100644
--- a/libgo/go/xml/read.go
+++ b/libgo/go/xml/read.go
@@ -139,8 +139,8 @@ import (
// to a freshly allocated value and then mapping the element to that value.
//
func Unmarshal(r io.Reader, val interface{}) os.Error {
- v, ok := reflect.NewValue(val).(*reflect.PtrValue)
- if !ok {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
return os.NewError("non-pointer passed to Unmarshal")
}
p := NewParser(r)
@@ -176,8 +176,8 @@ func (e *TagPathError) String() string {
// 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) os.Error {
- v, ok := reflect.NewValue(val).(*reflect.PtrValue)
- if !ok {
+ v := reflect.ValueOf(val)
+ if v.Kind() != reflect.Ptr {
return os.NewError("non-pointer passed to Unmarshal")
}
return p.unmarshal(v.Elem(), start)
@@ -219,14 +219,11 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
}
}
- if pv, ok := val.(*reflect.PtrValue); ok {
- if pv.Get() == 0 {
- zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
- pv.PointTo(zv)
- val = zv
- } else {
- val = pv.Elem()
+ if pv := val; pv.Kind() == reflect.Ptr {
+ if pv.IsNil() {
+ pv.Set(reflect.New(pv.Type().Elem()))
}
+ val = pv.Elem()
}
var (
@@ -237,17 +234,17 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
saveXML reflect.Value
saveXMLIndex int
saveXMLData []byte
- sv *reflect.StructValue
- styp *reflect.StructType
+ sv reflect.Value
+ styp reflect.Type
fieldPaths map[string]pathInfo
)
- switch v := val.(type) {
+ switch v := val; v.Kind() {
default:
return os.ErrorString("unknown type " + v.Type().String())
- case *reflect.SliceValue:
- typ := v.Type().(*reflect.SliceType)
+ case reflect.Slice:
+ typ := v.Type()
if typ.Elem().Kind() == reflect.Uint8 {
// []byte
saveData = v
@@ -269,23 +266,23 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
v.SetLen(n + 1)
// Recur to read element into slice.
- if err := p.unmarshal(v.Elem(n), start); err != nil {
+ if err := p.unmarshal(v.Index(n), start); err != nil {
v.SetLen(n)
return err
}
return nil
- case *reflect.BoolValue, *reflect.FloatValue, *reflect.IntValue, *reflect.UintValue, *reflect.StringValue:
+ case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
saveData = v
- case *reflect.StructValue:
+ case reflect.Struct:
if _, ok := v.Interface().(Name); ok {
- v.Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ v.Set(reflect.ValueOf(start.Name))
break
}
sv = v
- typ := sv.Type().(*reflect.StructType)
+ typ := sv.Type()
styp = typ
// Assign name.
if f, ok := typ.FieldByName("XMLName"); ok {
@@ -316,7 +313,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
if _, ok := v.Interface().(Name); !ok {
return UnmarshalError(sv.Type().String() + " field XMLName does not have type xml.Name")
}
- v.(*reflect.StructValue).Set(reflect.NewValue(start.Name).(*reflect.StructValue))
+ v.Set(reflect.ValueOf(start.Name))
}
// Assign attributes.
@@ -325,8 +322,8 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
f := typ.Field(i)
switch f.Tag {
case "attr":
- strv, ok := sv.FieldByIndex(f.Index).(*reflect.StringValue)
- if !ok {
+ strv := sv.FieldByIndex(f.Index)
+ if strv.Kind() != reflect.String {
return UnmarshalError(sv.Type().String() + " field " + f.Name + " has attr tag but is not type string")
}
// Look for attribute.
@@ -338,20 +335,20 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
break
}
}
- strv.Set(val)
+ strv.SetString(val)
case "comment":
- if saveComment == nil {
+ if !saveComment.IsValid() {
saveComment = sv.FieldByIndex(f.Index)
}
case "chardata":
- if saveData == nil {
+ if !saveData.IsValid() {
saveData = sv.FieldByIndex(f.Index)
}
case "innerxml":
- if saveXML == nil {
+ if !saveXML.IsValid() {
saveXML = sv.FieldByIndex(f.Index)
if p.saved == nil {
saveXMLIndex = 0
@@ -387,7 +384,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
Loop:
for {
var savedOffset int
- if saveXML != nil {
+ if saveXML.IsValid() {
savedOffset = p.savedOffset()
}
tok, err := p.Token()
@@ -398,7 +395,7 @@ Loop:
case StartElement:
// Sub-element.
// Look up by tag name.
- if sv != nil {
+ if sv.IsValid() {
k := fieldName(t.Name.Local)
if fieldPaths != nil {
@@ -437,7 +434,7 @@ Loop:
}
case EndElement:
- if saveXML != nil {
+ if saveXML.IsValid() {
saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
if saveXMLIndex == 0 {
p.saved = nil
@@ -446,12 +443,12 @@ Loop:
break Loop
case CharData:
- if saveData != nil {
+ if saveData.IsValid() {
data = append(data, t...)
}
case Comment:
- if saveComment != nil {
+ if saveComment.IsValid() {
comment = append(comment, t...)
}
}
@@ -479,50 +476,50 @@ Loop:
}
// Save accumulated data and comments
- switch t := saveData.(type) {
- case nil:
+ switch t := saveData; t.Kind() {
+ case reflect.Invalid:
// Probably a comment, handled below
default:
return os.ErrorString("cannot happen: unknown type " + t.Type().String())
- case *reflect.IntValue:
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if !getInt64() {
return err
}
- t.Set(itmp)
- case *reflect.UintValue:
+ t.SetInt(itmp)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if !getUint64() {
return err
}
- t.Set(utmp)
- case *reflect.FloatValue:
+ t.SetUint(utmp)
+ case reflect.Float32, reflect.Float64:
if !getFloat64() {
return err
}
- t.Set(ftmp)
- case *reflect.BoolValue:
+ t.SetFloat(ftmp)
+ case reflect.Bool:
value, err := strconv.Atob(strings.TrimSpace(string(data)))
if err != nil {
return err
}
- t.Set(value)
- case *reflect.StringValue:
- t.Set(string(data))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(data).(*reflect.SliceValue))
+ t.SetBool(value)
+ case reflect.String:
+ t.SetString(string(data))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(data))
}
- switch t := saveComment.(type) {
- case *reflect.StringValue:
- t.Set(string(comment))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(comment).(*reflect.SliceValue))
+ switch t := saveComment; t.Kind() {
+ case reflect.String:
+ t.SetString(string(comment))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(comment))
}
- switch t := saveXML.(type) {
- case *reflect.StringValue:
- t.Set(string(saveXMLData))
- case *reflect.SliceValue:
- t.Set(reflect.NewValue(saveXMLData).(*reflect.SliceValue))
+ switch t := saveXML; t.Kind() {
+ case reflect.String:
+ t.SetString(string(saveXMLData))
+ case reflect.Slice:
+ t.Set(reflect.ValueOf(saveXMLData))
}
return nil
@@ -537,7 +534,7 @@ type pathInfo struct {
// paths map with all paths leading to it ("a", "a>b", and "a>b>c").
// It is okay for paths to share a common, shorter prefix but not ok
// for one path to itself be a prefix of another.
-func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
+func addFieldPath(sv reflect.Value, paths map[string]pathInfo, path string, fieldIdx []int) os.Error {
if info, found := paths[path]; found {
return tagError(sv, info.fieldIdx, fieldIdx)
}
@@ -560,8 +557,8 @@ func addFieldPath(sv *reflect.StructValue, paths map[string]pathInfo, path strin
}
-func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error {
- t := sv.Type().(*reflect.StructType)
+func tagError(sv reflect.Value, idx1 []int, idx2 []int) os.Error {
+ t := sv.Type()
f1 := t.FieldByIndex(idx1)
f2 := t.FieldByIndex(idx2)
return &TagPathError{t, f1.Name, f1.Tag, f2.Name, f2.Tag}
@@ -569,7 +566,7 @@ func tagError(sv *reflect.StructValue, idx1 []int, idx2 []int) os.Error {
// unmarshalPaths walks down an XML structure looking for
// wanted paths, and calls unmarshal on them.
-func (p *Parser) unmarshalPaths(sv *reflect.StructValue, paths map[string]pathInfo, path string, start *StartElement) os.Error {
+func (p *Parser) unmarshalPaths(sv reflect.Value, paths map[string]pathInfo, path string, start *StartElement) os.Error {
if info, _ := paths[path]; info.complete {
return p.unmarshal(sv.FieldByIndex(info.fieldIdx), start)
}
diff --git a/libgo/go/xml/read_test.go b/libgo/go/xml/read_test.go
index a6b9a8e..d4ae370 100644
--- a/libgo/go/xml/read_test.go
+++ b/libgo/go/xml/read_test.go
@@ -288,9 +288,7 @@ var pathTests = []interface{}{
func TestUnmarshalPaths(t *testing.T) {
for _, pt := range pathTests {
- p := reflect.MakeZero(reflect.NewValue(pt).Type()).(*reflect.PtrValue)
- p.PointTo(reflect.MakeZero(p.Type().(*reflect.PtrType).Elem()))
- v := p.Interface()
+ v := reflect.New(reflect.TypeOf(pt).Elem()).Interface()
if err := Unmarshal(StringReader(pathTestString), v); err != nil {
t.Fatalf("Unmarshal: %s", err)
}
@@ -315,8 +313,8 @@ type BadPathTestB struct {
var badPathTests = []struct {
v, e interface{}
}{
- {&BadPathTestA{}, &TagPathError{reflect.Typeof(BadPathTestA{}), "First", "items>item1", "Second", "items>"}},
- {&BadPathTestB{}, &TagPathError{reflect.Typeof(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
+ {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items>"}},
+ {&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}},
}
func TestUnmarshalBadPaths(t *testing.T) {
diff --git a/libgo/go/xml/xml.go b/libgo/go/xml/xml.go
index f92abe8..42d8b98 100644
--- a/libgo/go/xml/xml.go
+++ b/libgo/go/xml/xml.go
@@ -163,6 +163,13 @@ type Parser struct {
// "quot": `"`,
Entity map[string]string
+ // CharsetReader, if non-nil, defines a function to generate
+ // charset-conversion readers, converting from the provided
+ // non-UTF-8 charset into UTF-8. If CharsetReader is nil or
+ // returns an error, parsing stops with an error. One of the
+ // the CharsetReader's result values must be non-nil.
+ CharsetReader func(charset string, input io.Reader) (io.Reader, os.Error)
+
r io.ByteReader
buf bytes.Buffer
saved *bytes.Buffer
@@ -186,17 +193,7 @@ func NewParser(r io.Reader) *Parser {
line: 1,
Strict: true,
}
-
- // 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
- } else {
- p.r = bufio.NewReader(r)
- }
-
+ p.switchToReader(r)
return p
}
@@ -290,6 +287,18 @@ func (p *Parser) translate(n *Name, isElementName bool) {
}
}
+func (p *Parser) 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
+ } else {
+ p.r = bufio.NewReader(r)
+ }
+}
+
// Parsing state - stack holds old name space translations
// and the current set of open elements. The translations to pop when
// ending a given tag are *below* it on the stack, which is
@@ -487,6 +496,25 @@ func (p *Parser) RawToken() (Token, os.Error) {
}
data := p.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
+ }
+ newr, err := p.CharsetReader(enc, p.r.(io.Reader))
+ if err != nil {
+ p.err = fmt.Errorf("xml: opening charset %q: %v", enc, err)
+ return nil, p.err
+ }
+ if newr == nil {
+ panic("CharsetReader returned a nil Reader for charset " + enc)
+ }
+ p.switchToReader(newr)
+ }
+ }
return ProcInst{target, data}, nil
case '!':
@@ -1633,3 +1661,26 @@ func Escape(w io.Writer, s []byte) {
}
w.Write(s[last:])
}
+
+// procInstEncoding parses the `encoding="..."` or `encoding='...'`
+// value out of the provided string, returning "" if not found.
+func procInstEncoding(s string) string {
+ // TODO: this parsing is somewhat lame and not exact.
+ // It works for all actual cases, though.
+ idx := strings.Index(s, "encoding=")
+ if idx == -1 {
+ return ""
+ }
+ v := s[idx+len("encoding="):]
+ if v == "" {
+ return ""
+ }
+ if v[0] != '\'' && v[0] != '"' {
+ return ""
+ }
+ idx = strings.IndexRune(v[1:], int(v[0]))
+ if idx == -1 {
+ return ""
+ }
+ return v[1 : idx+1]
+}
diff --git a/libgo/go/xml/xml_test.go b/libgo/go/xml/xml_test.go
index 887bc3d..4e51cd5 100644
--- a/libgo/go/xml/xml_test.go
+++ b/libgo/go/xml/xml_test.go
@@ -9,6 +9,7 @@ import (
"io"
"os"
"reflect"
+ "strings"
"testing"
)
@@ -96,6 +97,19 @@ var cookedTokens = []Token{
Comment([]byte(" missing final newline ")),
}
+const testInputAltEncoding = `
+<?xml version="1.0" encoding="x-testing-uppercase"?>
+<TAG>VALUE</TAG>`
+
+var rawTokensAltEncoding = []Token{
+ CharData([]byte("\n")),
+ ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
+ CharData([]byte("\n")),
+ StartElement{Name{"", "tag"}, nil},
+ CharData([]byte("value")),
+ EndElement{Name{"", "tag"}},
+}
+
var xmlInput = []string{
// unexpected EOF cases
"<",
@@ -173,7 +187,64 @@ func StringReader(s string) io.Reader { return &stringReader{s, 0} }
func TestRawToken(t *testing.T) {
p := NewParser(StringReader(testInput))
+ testRawToken(t, p, rawTokens)
+}
+
+type downCaser struct {
+ t *testing.T
+ r io.ByteReader
+}
+func (d *downCaser) ReadByte() (c byte, err os.Error) {
+ c, err = d.r.ReadByte()
+ if c >= 'A' && c <= 'Z' {
+ c += 'a' - 'A'
+ }
+ return
+}
+
+func (d *downCaser) Read(p []byte) (int, os.Error) {
+ d.t.Fatalf("unexpected Read call on downCaser reader")
+ return 0, os.EINVAL
+}
+
+func TestRawTokenAltEncoding(t *testing.T) {
+ sawEncoding := ""
+ p := NewParser(StringReader(testInputAltEncoding))
+ p.CharsetReader = func(charset string, input io.Reader) (io.Reader, os.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)
+}
+
+func TestRawTokenAltEncodingNoConverter(t *testing.T) {
+ p := NewParser(StringReader(testInputAltEncoding))
+ token, err := p.RawToken()
+ if token == nil {
+ t.Fatalf("expected a token on first RawToken call")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ token, err = p.RawToken()
+ if token != nil {
+ t.Errorf("expected a nil token; got %#v", token)
+ }
+ if err == nil {
+ t.Fatalf("expected an error on second RawToken call")
+ }
+ const encoding = "x-testing-uppercase"
+ if !strings.Contains(err.String(), encoding) {
+ t.Errorf("expected error to contain %q; got error: %v",
+ encoding, err)
+ }
+}
+
+func testRawToken(t *testing.T, p *Parser, rawTokens []Token) {
for i, want := range rawTokens {
have, err := p.RawToken()
if err != nil {
@@ -258,47 +329,51 @@ func TestSyntax(t *testing.T) {
}
type allScalars struct {
- True1 bool
- True2 bool
- False1 bool
- False2 bool
- Int int
- Int8 int8
- Int16 int16
- Int32 int32
- Int64 int64
- Uint int
- Uint8 uint8
- Uint16 uint16
- Uint32 uint32
- Uint64 uint64
- Uintptr uintptr
- Float32 float32
- Float64 float64
- String string
+ True1 bool
+ True2 bool
+ False1 bool
+ False2 bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint int
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Uintptr uintptr
+ Float32 float32
+ Float64 float64
+ String string
+ PtrString *string
}
var all = allScalars{
- True1: true,
- True2: true,
- False1: false,
- False2: false,
- Int: 1,
- Int8: -2,
- Int16: 3,
- Int32: -4,
- Int64: 5,
- Uint: 6,
- Uint8: 7,
- Uint16: 8,
- Uint32: 9,
- Uint64: 10,
- Uintptr: 11,
- Float32: 13.0,
- Float64: 14.0,
- String: "15",
+ True1: true,
+ True2: true,
+ False1: false,
+ False2: false,
+ Int: 1,
+ Int8: -2,
+ Int16: 3,
+ Int32: -4,
+ Int64: 5,
+ Uint: 6,
+ Uint8: 7,
+ Uint16: 8,
+ Uint32: 9,
+ Uint64: 10,
+ Uintptr: 11,
+ Float32: 13.0,
+ Float64: 14.0,
+ String: "15",
+ PtrString: &sixteen,
}
+var sixteen = "16"
+
const testScalarsInput = `<allscalars>
<true1>true</true1>
<true2>1</true2>
@@ -319,6 +394,7 @@ const testScalarsInput = `<allscalars>
<float32>13.0</float32>
<float64>14.0</float64>
<string>15</string>
+ <ptrstring>16</ptrstring>
</allscalars>`
func TestAllScalars(t *testing.T) {
@@ -330,7 +406,7 @@ func TestAllScalars(t *testing.T) {
t.Fatal(err)
}
if !reflect.DeepEqual(a, all) {
- t.Errorf("expected %+v got %+v", all, a)
+ t.Errorf("have %+v want %+v", a, all)
}
}
@@ -483,3 +559,26 @@ func TestDisallowedCharacters(t *testing.T) {
}
}
}
+
+type procInstEncodingTest struct {
+ expect, got string
+}
+
+var procInstTests = []struct {
+ input, expect string
+}{
+ {`version="1.0" encoding="utf-8"`, "utf-8"},
+ {`version="1.0" encoding='utf-8'`, "utf-8"},
+ {`version="1.0" encoding='utf-8' `, "utf-8"},
+ {`version="1.0" encoding=utf-8`, ""},
+ {`encoding="FOO" `, "FOO"},
+}
+
+func TestProcInstEncoding(t *testing.T) {
+ for _, test := range procInstTests {
+ got := procInstEncoding(test.input)
+ if got != test.expect {
+ t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect)
+ }
+ }
+}