]> Cypherpunks repositories - gostls13.git/commitdiff
json: fix quoted strings in Marshal
authorSergei Skorobogatov <skorobo@rambler.ru>
Mon, 22 Feb 2010 22:32:40 +0000 (14:32 -0800)
committerRuss Cox <rsc@golang.org>
Mon, 22 Feb 2010 22:32:40 +0000 (14:32 -0800)
R=rsc
CC=golang-dev
https://golang.org/cl/217047

src/pkg/json/struct.go
src/pkg/json/struct_test.go

index 955ec7c875524ca06f01a5a222c2253781e7362a..3357e04a3c8b781856a4330f22a29f59a87fa5e5 100644 (file)
@@ -317,76 +317,94 @@ type MarshalError struct {
 func (e *MarshalError) String() string {
        return "json cannot encode value of type " + e.T.String()
 }
-func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) os.Error {
-       fmt.Fprint(w, "[")
+
+func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) (err os.Error) {
+       if _, err = fmt.Fprint(w, "["); err != nil {
+               return
+       }
 
        for i := 0; i < val.Len(); i++ {
-               if err := writeValue(w, val.Elem(i)); err != nil {
-                       return err
+               if err = writeValue(w, val.Elem(i)); err != nil {
+                       return
                }
 
                if i < val.Len()-1 {
-                       fmt.Fprint(w, ",")
+                       if _, err = fmt.Fprint(w, ","); err != nil {
+                               return
+                       }
                }
        }
 
-       fmt.Fprint(w, "]")
-       return nil
+       _, err = fmt.Fprint(w, "]")
+       return
 }
 
-func writeMap(w io.Writer, val *reflect.MapValue) os.Error {
+func writeMap(w io.Writer, val *reflect.MapValue) (err os.Error) {
        key := val.Type().(*reflect.MapType).Key()
        if _, ok := key.(*reflect.StringType); !ok {
                return &MarshalError{val.Type()}
        }
 
        keys := val.Keys()
-       fmt.Fprint(w, "{")
+       if _, err = fmt.Fprint(w, "{"); err != nil {
+               return
+       }
+
        for i := 0; i < len(keys); i++ {
-               fmt.Fprintf(w, "%q:", keys[i].(*reflect.StringValue).Get())
+               if _, err = fmt.Fprintf(w, "%s:", Quote(keys[i].(*reflect.StringValue).Get())); err != nil {
+                       return
+               }
 
-               if err := writeValue(w, val.Elem(keys[i])); err != nil {
-                       return err
+               if err = writeValue(w, val.Elem(keys[i])); err != nil {
+                       return
                }
 
                if i < len(keys)-1 {
-                       fmt.Fprint(w, ",")
+                       if _, err = fmt.Fprint(w, ","); err != nil {
+                               return
+                       }
                }
        }
 
-       fmt.Fprint(w, "}")
-       return nil
+       _, err = fmt.Fprint(w, "}")
+       return
 }
 
-func writeStruct(w io.Writer, val *reflect.StructValue) os.Error {
-       fmt.Fprint(w, "{")
+func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) {
+       if _, err = fmt.Fprint(w, "{"); err != nil {
+               return
+       }
 
        typ := val.Type().(*reflect.StructType)
 
        for i := 0; i < val.NumField(); i++ {
                fieldValue := val.Field(i)
-               fmt.Fprintf(w, "%q:", typ.Field(i).Name)
-               if err := writeValue(w, fieldValue); err != nil {
-                       return err
+               if _, err = fmt.Fprintf(w, "%s:", Quote(typ.Field(i).Name)); err != nil {
+                       return
+               }
+               if err = writeValue(w, fieldValue); err != nil {
+                       return
                }
                if i < val.NumField()-1 {
-                       fmt.Fprint(w, ",")
+                       if _, err = fmt.Fprint(w, ","); err != nil {
+                               return
+                       }
                }
        }
 
-       fmt.Fprint(w, "}")
-       return nil
+       _, err = fmt.Fprint(w, "}")
+       return
 }
 
 func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
        if val == nil {
-               fmt.Fprint(w, "null")
+               _, err = fmt.Fprint(w, "null")
                return
        }
 
        switch v := val.(type) {
        case *reflect.StringValue:
-               fmt.Fprintf(w, "%q", v.Get())
+               _, err = fmt.Fprint(w, Quote(v.Get()))
        case *reflect.ArrayValue:
                err = writeArrayOrSlice(w, v)
        case *reflect.SliceValue:
@@ -396,27 +414,42 @@ func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
        case *reflect.StructValue:
                err = writeStruct(w, v)
        case *reflect.ChanValue,
-               *reflect.UnsafePointerValue:
+               *reflect.UnsafePointerValue,
+               *reflect.FuncValue:
                err = &MarshalError{val.Type()}
        case *reflect.InterfaceValue:
                if v.IsNil() {
-                       fmt.Fprint(w, "null")
+                       _, err = fmt.Fprint(w, "null")
                } else {
                        err = writeValue(w, v.Elem())
                }
        case *reflect.PtrValue:
                if v.IsNil() {
-                       fmt.Fprint(w, "null")
+                       _, err = fmt.Fprint(w, "null")
                } else {
                        err = writeValue(w, v.Elem())
                }
+       case *reflect.UintptrValue:
+               _, err = fmt.Fprintf(w, "%d", v.Get())
+       case *reflect.Uint64Value:
+               _, err = fmt.Fprintf(w, "%d", v.Get())
+       case *reflect.Uint32Value:
+               _, err = fmt.Fprintf(w, "%d", v.Get())
+       case *reflect.Uint16Value:
+               _, err = fmt.Fprintf(w, "%d", v.Get())
+       case *reflect.Uint8Value:
+               _, err = fmt.Fprintf(w, "%d", v.Get())
        default:
                value := val.(reflect.Value)
-               fmt.Fprint(w, value.Interface())
+               _, err = fmt.Fprintf(w, "%#v", value.Interface())
        }
        return
 }
 
+// Marshal writes the JSON encoding of val to w.
+//
+// Due to limitations in JSON, val cannot include cyclic data
+// structures, channels, functions, or maps.
 func Marshal(w io.Writer, val interface{}) os.Error {
        return writeValue(w, reflect.NewValue(val))
 }
index f1440c4139b20bb01e9c2aa5f01c8f00c7d60961..66d6e79c2886d04d1dadb9c3d60b4f47c8ddb69f 100644 (file)
@@ -181,6 +181,18 @@ type OneField struct {
        a int
 }
 
+type ScalarWithString int
+
+const (
+       AA ScalarWithString = iota
+       BB
+       CC
+)
+
+var scalarStrings = []string{"AA", "BB", "CC"}
+
+func (x ScalarWithString) String() string { return scalarStrings[x] }
+
 var marshalTests = []marshalTest{
        // basic string
        marshalTest{nil, "null"},
@@ -210,6 +222,17 @@ var marshalTests = []marshalTest{
        marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`},
        marshalTest{map[string]interface{}{"hi": 3}, `{"hi":3}`},
        marshalTest{&OneField{3}, `{"a":3}`},
+       marshalTest{"\x05\x06", `"\u0005\u0006"`},
+       marshalTest{uintptr(50000), "50000"},
+       marshalTest{uint64(50000), "50000"},
+       marshalTest{uint32(50000), "50000"},
+       marshalTest{uint16(50000), "50000"},
+       marshalTest{uint8(50), "50"},
+       marshalTest{int64(50000), "50000"},
+       marshalTest{int32(50000), "50000"},
+       marshalTest{int16(10000), "10000"},
+       marshalTest{int8(50), "50"},
+       marshalTest{BB, "1"},
 }
 
 func TestMarshal(t *testing.T) {