summaryrefslogtreecommitdiff
path: root/src/pkg/json/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/json/decode.go')
-rw-r--r--src/pkg/json/decode.go50
1 files changed, 38 insertions, 12 deletions
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
index 3f6965009..c704cacbd 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/json/decode.go
@@ -82,6 +82,18 @@ func (e *UnmarshalTypeError) String() string {
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
}
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type *reflect.StructType
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)
type InvalidUnmarshalError struct {
@@ -116,7 +128,9 @@ func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
}
d.scan.reset()
- d.value(pv.Elem())
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
return d.savedError
}
@@ -330,7 +344,7 @@ func (d *decodeState) array(v reflect.Value) {
newcap = 4
}
newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
- reflect.ArrayCopy(newv, sv)
+ reflect.Copy(newv, sv)
sv.Set(newv)
}
if i >= av.Len() && sv != nil {
@@ -450,20 +464,32 @@ func (d *decodeState) object(v reflect.Value) {
if mv != nil {
subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
} else {
+ var f reflect.StructField
+ var ok bool
// First try for field with that tag.
+ st := sv.Type().(*reflect.StructType)
for i := 0; i < sv.NumField(); i++ {
- f := sv.Type().(*reflect.StructType).Field(i)
+ f = st.Field(i)
if f.Tag == key {
- subv = sv.Field(i)
+ ok = true
break
}
}
- if subv == nil {
+ if !ok {
// Second, exact match.
- subv = sv.FieldByName(key)
- if subv == nil {
- // Third, case-insensitive match.
- subv = sv.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
}
}
}
@@ -805,13 +831,13 @@ func unquote(s []byte) (t string, ok bool) {
if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
// A valid pair; consume.
r += 6
- w += utf8.EncodeRune(dec, b[w:])
+ w += utf8.EncodeRune(b[w:], dec)
break
}
// Invalid surrogate; fall back to replacement rune.
rune = unicode.ReplacementChar
}
- w += utf8.EncodeRune(rune, b[w:])
+ w += utf8.EncodeRune(b[w:], rune)
}
// Quote, control characters are invalid.
@@ -828,7 +854,7 @@ func unquote(s []byte) (t string, ok bool) {
default:
rune, size := utf8.DecodeRune(s[r:])
r += size
- w += utf8.EncodeRune(rune, b[w:])
+ w += utf8.EncodeRune(b[w:], rune)
}
}
return string(b[0:w]), true