1package msgp 2 3import ( 4 "bufio" 5 "encoding/base64" 6 "encoding/json" 7 "io" 8 "strconv" 9 "time" 10) 11 12var unfuns [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error) 13 14func init() { 15 16 // NOTE(pmh): this is best expressed as a jump table, 17 // but gc doesn't do that yet. revisit post-go1.5. 18 unfuns = [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error){ 19 StrType: rwStringBytes, 20 BinType: rwBytesBytes, 21 MapType: rwMapBytes, 22 ArrayType: rwArrayBytes, 23 Float64Type: rwFloat64Bytes, 24 Float32Type: rwFloat32Bytes, 25 BoolType: rwBoolBytes, 26 IntType: rwIntBytes, 27 UintType: rwUintBytes, 28 NilType: rwNullBytes, 29 ExtensionType: rwExtensionBytes, 30 Complex64Type: rwExtensionBytes, 31 Complex128Type: rwExtensionBytes, 32 TimeType: rwTimeBytes, 33 } 34} 35 36// UnmarshalAsJSON takes raw messagepack and writes 37// it as JSON to 'w'. If an error is returned, the 38// bytes not translated will also be returned. If 39// no errors are encountered, the length of the returned 40// slice will be zero. 41func UnmarshalAsJSON(w io.Writer, msg []byte) ([]byte, error) { 42 var ( 43 scratch []byte 44 cast bool 45 dst jsWriter 46 err error 47 ) 48 if jsw, ok := w.(jsWriter); ok { 49 dst = jsw 50 cast = true 51 } else { 52 dst = bufio.NewWriterSize(w, 512) 53 } 54 for len(msg) > 0 && err == nil { 55 msg, scratch, err = writeNext(dst, msg, scratch) 56 } 57 if !cast && err == nil { 58 err = dst.(*bufio.Writer).Flush() 59 } 60 return msg, err 61} 62 63func writeNext(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 64 if len(msg) < 1 { 65 return msg, scratch, ErrShortBytes 66 } 67 t := getType(msg[0]) 68 if t == InvalidType { 69 return msg, scratch, InvalidPrefixError(msg[0]) 70 } 71 if t == ExtensionType { 72 et, err := peekExtension(msg) 73 if err != nil { 74 return nil, scratch, err 75 } 76 if et == TimeExtension { 77 t = TimeType 78 } 79 } 80 return unfuns[t](w, msg, scratch) 81} 82 83func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 84 sz, msg, err := ReadArrayHeaderBytes(msg) 85 if err != nil { 86 return msg, scratch, err 87 } 88 err = w.WriteByte('[') 89 if err != nil { 90 return msg, scratch, err 91 } 92 for i := uint32(0); i < sz; i++ { 93 if i != 0 { 94 err = w.WriteByte(',') 95 if err != nil { 96 return msg, scratch, err 97 } 98 } 99 msg, scratch, err = writeNext(w, msg, scratch) 100 if err != nil { 101 return msg, scratch, err 102 } 103 } 104 err = w.WriteByte(']') 105 return msg, scratch, err 106} 107 108func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 109 sz, msg, err := ReadMapHeaderBytes(msg) 110 if err != nil { 111 return msg, scratch, err 112 } 113 err = w.WriteByte('{') 114 if err != nil { 115 return msg, scratch, err 116 } 117 for i := uint32(0); i < sz; i++ { 118 if i != 0 { 119 err = w.WriteByte(',') 120 if err != nil { 121 return msg, scratch, err 122 } 123 } 124 msg, scratch, err = rwMapKeyBytes(w, msg, scratch) 125 if err != nil { 126 return msg, scratch, err 127 } 128 err = w.WriteByte(':') 129 if err != nil { 130 return msg, scratch, err 131 } 132 msg, scratch, err = writeNext(w, msg, scratch) 133 if err != nil { 134 return msg, scratch, err 135 } 136 } 137 err = w.WriteByte('}') 138 return msg, scratch, err 139} 140 141func rwMapKeyBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 142 msg, scratch, err := rwStringBytes(w, msg, scratch) 143 if err != nil { 144 if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType { 145 return rwBytesBytes(w, msg, scratch) 146 } 147 } 148 return msg, scratch, err 149} 150 151func rwStringBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 152 str, msg, err := ReadStringZC(msg) 153 if err != nil { 154 return msg, scratch, err 155 } 156 _, err = rwquoted(w, str) 157 return msg, scratch, err 158} 159 160func rwBytesBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 161 bts, msg, err := ReadBytesZC(msg) 162 if err != nil { 163 return msg, scratch, err 164 } 165 l := base64.StdEncoding.EncodedLen(len(bts)) 166 if cap(scratch) >= l { 167 scratch = scratch[0:l] 168 } else { 169 scratch = make([]byte, l) 170 } 171 base64.StdEncoding.Encode(scratch, bts) 172 err = w.WriteByte('"') 173 if err != nil { 174 return msg, scratch, err 175 } 176 _, err = w.Write(scratch) 177 if err != nil { 178 return msg, scratch, err 179 } 180 err = w.WriteByte('"') 181 return msg, scratch, err 182} 183 184func rwNullBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 185 msg, err := ReadNilBytes(msg) 186 if err != nil { 187 return msg, scratch, err 188 } 189 _, err = w.Write(null) 190 return msg, scratch, err 191} 192 193func rwBoolBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 194 b, msg, err := ReadBoolBytes(msg) 195 if err != nil { 196 return msg, scratch, err 197 } 198 if b { 199 _, err = w.WriteString("true") 200 return msg, scratch, err 201 } 202 _, err = w.WriteString("false") 203 return msg, scratch, err 204} 205 206func rwIntBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 207 i, msg, err := ReadInt64Bytes(msg) 208 if err != nil { 209 return msg, scratch, err 210 } 211 scratch = strconv.AppendInt(scratch[0:0], i, 10) 212 _, err = w.Write(scratch) 213 return msg, scratch, err 214} 215 216func rwUintBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 217 u, msg, err := ReadUint64Bytes(msg) 218 if err != nil { 219 return msg, scratch, err 220 } 221 scratch = strconv.AppendUint(scratch[0:0], u, 10) 222 _, err = w.Write(scratch) 223 return msg, scratch, err 224} 225 226func rwFloatBytes(w jsWriter, msg []byte, f64 bool, scratch []byte) ([]byte, []byte, error) { 227 var f float64 228 var err error 229 var sz int 230 if f64 { 231 sz = 64 232 f, msg, err = ReadFloat64Bytes(msg) 233 } else { 234 sz = 32 235 var v float32 236 v, msg, err = ReadFloat32Bytes(msg) 237 f = float64(v) 238 } 239 if err != nil { 240 return msg, scratch, err 241 } 242 scratch = strconv.AppendFloat(scratch, f, 'f', -1, sz) 243 _, err = w.Write(scratch) 244 return msg, scratch, err 245} 246 247func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 248 var f float32 249 var err error 250 f, msg, err = ReadFloat32Bytes(msg) 251 if err != nil { 252 return msg, scratch, err 253 } 254 scratch = strconv.AppendFloat(scratch[:0], float64(f), 'f', -1, 32) 255 _, err = w.Write(scratch) 256 return msg, scratch, err 257} 258 259func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 260 var f float64 261 var err error 262 f, msg, err = ReadFloat64Bytes(msg) 263 if err != nil { 264 return msg, scratch, err 265 } 266 scratch = strconv.AppendFloat(scratch[:0], f, 'f', -1, 64) 267 _, err = w.Write(scratch) 268 return msg, scratch, err 269} 270 271func rwTimeBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 272 var t time.Time 273 var err error 274 t, msg, err = ReadTimeBytes(msg) 275 if err != nil { 276 return msg, scratch, err 277 } 278 bts, err := t.MarshalJSON() 279 if err != nil { 280 return msg, scratch, err 281 } 282 _, err = w.Write(bts) 283 return msg, scratch, err 284} 285 286func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) { 287 var err error 288 var et int8 289 et, err = peekExtension(msg) 290 if err != nil { 291 return msg, scratch, err 292 } 293 294 // if it's time.Time 295 if et == TimeExtension { 296 var tm time.Time 297 tm, msg, err = ReadTimeBytes(msg) 298 if err != nil { 299 return msg, scratch, err 300 } 301 bts, err := tm.MarshalJSON() 302 if err != nil { 303 return msg, scratch, err 304 } 305 _, err = w.Write(bts) 306 return msg, scratch, err 307 } 308 309 // if the extension is registered, 310 // use its canonical JSON form 311 if f, ok := extensionReg[et]; ok { 312 e := f() 313 msg, err = ReadExtensionBytes(msg, e) 314 if err != nil { 315 return msg, scratch, err 316 } 317 bts, err := json.Marshal(e) 318 if err != nil { 319 return msg, scratch, err 320 } 321 _, err = w.Write(bts) 322 return msg, scratch, err 323 } 324 325 // otherwise, write `{"type": <num>, "data": "<base64data>"}` 326 r := RawExtension{} 327 r.Type = et 328 msg, err = ReadExtensionBytes(msg, &r) 329 if err != nil { 330 return msg, scratch, err 331 } 332 scratch, err = writeExt(w, r, scratch) 333 return msg, scratch, err 334} 335 336func writeExt(w jsWriter, r RawExtension, scratch []byte) ([]byte, error) { 337 _, err := w.WriteString(`{"type":`) 338 if err != nil { 339 return scratch, err 340 } 341 scratch = strconv.AppendInt(scratch[0:0], int64(r.Type), 10) 342 _, err = w.Write(scratch) 343 if err != nil { 344 return scratch, err 345 } 346 _, err = w.WriteString(`,"data":"`) 347 if err != nil { 348 return scratch, err 349 } 350 l := base64.StdEncoding.EncodedLen(len(r.Data)) 351 if cap(scratch) >= l { 352 scratch = scratch[0:l] 353 } else { 354 scratch = make([]byte, l) 355 } 356 base64.StdEncoding.Encode(scratch, r.Data) 357 _, err = w.Write(scratch) 358 if err != nil { 359 return scratch, err 360 } 361 _, err = w.WriteString(`"}`) 362 return scratch, err 363} 364