Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / aws / aws-sdk-go / private / protocol / json / jsonutil / unmarshal.go
1 package jsonutil
2
3 import (
4         "encoding/base64"
5         "encoding/json"
6         "fmt"
7         "io"
8         "io/ioutil"
9         "reflect"
10         "time"
11 )
12
13 // UnmarshalJSON reads a stream and unmarshals the results in object v.
14 func UnmarshalJSON(v interface{}, stream io.Reader) error {
15         var out interface{}
16
17         b, err := ioutil.ReadAll(stream)
18         if err != nil {
19                 return err
20         }
21
22         if len(b) == 0 {
23                 return nil
24         }
25
26         if err := json.Unmarshal(b, &out); err != nil {
27                 return err
28         }
29
30         return unmarshalAny(reflect.ValueOf(v), out, "")
31 }
32
33 func unmarshalAny(value reflect.Value, data interface{}, tag reflect.StructTag) error {
34         vtype := value.Type()
35         if vtype.Kind() == reflect.Ptr {
36                 vtype = vtype.Elem() // check kind of actual element type
37         }
38
39         t := tag.Get("type")
40         if t == "" {
41                 switch vtype.Kind() {
42                 case reflect.Struct:
43                         // also it can't be a time object
44                         if _, ok := value.Interface().(*time.Time); !ok {
45                                 t = "structure"
46                         }
47                 case reflect.Slice:
48                         // also it can't be a byte slice
49                         if _, ok := value.Interface().([]byte); !ok {
50                                 t = "list"
51                         }
52                 case reflect.Map:
53                         t = "map"
54                 }
55         }
56
57         switch t {
58         case "structure":
59                 if field, ok := vtype.FieldByName("_"); ok {
60                         tag = field.Tag
61                 }
62                 return unmarshalStruct(value, data, tag)
63         case "list":
64                 return unmarshalList(value, data, tag)
65         case "map":
66                 return unmarshalMap(value, data, tag)
67         default:
68                 return unmarshalScalar(value, data, tag)
69         }
70 }
71
72 func unmarshalStruct(value reflect.Value, data interface{}, tag reflect.StructTag) error {
73         if data == nil {
74                 return nil
75         }
76         mapData, ok := data.(map[string]interface{})
77         if !ok {
78                 return fmt.Errorf("JSON value is not a structure (%#v)", data)
79         }
80
81         t := value.Type()
82         if value.Kind() == reflect.Ptr {
83                 if value.IsNil() { // create the structure if it's nil
84                         s := reflect.New(value.Type().Elem())
85                         value.Set(s)
86                         value = s
87                 }
88
89                 value = value.Elem()
90                 t = t.Elem()
91         }
92
93         // unwrap any payloads
94         if payload := tag.Get("payload"); payload != "" {
95                 field, _ := t.FieldByName(payload)
96                 return unmarshalAny(value.FieldByName(payload), data, field.Tag)
97         }
98
99         for i := 0; i < t.NumField(); i++ {
100                 field := t.Field(i)
101                 if field.PkgPath != "" {
102                         continue // ignore unexported fields
103                 }
104
105                 // figure out what this field is called
106                 name := field.Name
107                 if locName := field.Tag.Get("locationName"); locName != "" {
108                         name = locName
109                 }
110
111                 member := value.FieldByIndex(field.Index)
112                 err := unmarshalAny(member, mapData[name], field.Tag)
113                 if err != nil {
114                         return err
115                 }
116         }
117         return nil
118 }
119
120 func unmarshalList(value reflect.Value, data interface{}, tag reflect.StructTag) error {
121         if data == nil {
122                 return nil
123         }
124         listData, ok := data.([]interface{})
125         if !ok {
126                 return fmt.Errorf("JSON value is not a list (%#v)", data)
127         }
128
129         if value.IsNil() {
130                 l := len(listData)
131                 value.Set(reflect.MakeSlice(value.Type(), l, l))
132         }
133
134         for i, c := range listData {
135                 err := unmarshalAny(value.Index(i), c, "")
136                 if err != nil {
137                         return err
138                 }
139         }
140
141         return nil
142 }
143
144 func unmarshalMap(value reflect.Value, data interface{}, tag reflect.StructTag) error {
145         if data == nil {
146                 return nil
147         }
148         mapData, ok := data.(map[string]interface{})
149         if !ok {
150                 return fmt.Errorf("JSON value is not a map (%#v)", data)
151         }
152
153         if value.IsNil() {
154                 value.Set(reflect.MakeMap(value.Type()))
155         }
156
157         for k, v := range mapData {
158                 kvalue := reflect.ValueOf(k)
159                 vvalue := reflect.New(value.Type().Elem()).Elem()
160
161                 unmarshalAny(vvalue, v, "")
162                 value.SetMapIndex(kvalue, vvalue)
163         }
164
165         return nil
166 }
167
168 func unmarshalScalar(value reflect.Value, data interface{}, tag reflect.StructTag) error {
169         errf := func() error {
170                 return fmt.Errorf("unsupported value: %v (%s)", value.Interface(), value.Type())
171         }
172
173         switch d := data.(type) {
174         case nil:
175                 return nil // nothing to do here
176         case string:
177                 switch value.Interface().(type) {
178                 case *string:
179                         value.Set(reflect.ValueOf(&d))
180                 case []byte:
181                         b, err := base64.StdEncoding.DecodeString(d)
182                         if err != nil {
183                                 return err
184                         }
185                         value.Set(reflect.ValueOf(b))
186                 default:
187                         return errf()
188                 }
189         case float64:
190                 switch value.Interface().(type) {
191                 case *int64:
192                         di := int64(d)
193                         value.Set(reflect.ValueOf(&di))
194                 case *float64:
195                         value.Set(reflect.ValueOf(&d))
196                 case *time.Time:
197                         t := time.Unix(int64(d), 0).UTC()
198                         value.Set(reflect.ValueOf(&t))
199                 default:
200                         return errf()
201                 }
202         case bool:
203                 switch value.Interface().(type) {
204                 case *bool:
205                         value.Set(reflect.ValueOf(&d))
206                 default:
207                         return errf()
208                 }
209         default:
210                 return fmt.Errorf("unsupported JSON value (%v)", data)
211         }
212         return nil
213 }