From c15b4d116cb805508fd5862d8761a88076b3cc8e Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Wed, 19 Jul 2017 12:04:22 +0800 Subject: [PATCH] #139 unmarshal non base64 into []byte --- feature_reflect.go | 8 ++++++-- feature_reflect_native.go | 40 +++++++++++++++++++++---------------- jsoniter_array_test.go | 13 +++++++++++- jsoniter_large_file_test.go | 2 +- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/feature_reflect.go b/feature_reflect.go index 852d580..444f440 100644 --- a/feature_reflect.go +++ b/feature_reflect.go @@ -281,7 +281,11 @@ func createDecoderOfType(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error return &jsonNumberCodec{}, nil } if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { - return &base64Codec{}, nil + sliceDecoder, err := prefix("[slice]").addToDecoder(decoderOfSlice(cfg, typ)) + if err != nil { + return nil, err + } + return &base64Codec{sliceDecoder: sliceDecoder}, nil } if typ.Implements(unmarshalerType) { templateInterface := reflect.New(typ).Elem().Interface() @@ -440,7 +444,7 @@ func createEncoderOfType(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error return &jsonNumberCodec{}, nil } if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 { - return &base64Codec{typ}, nil + return &base64Codec{}, nil } if typ.Implements(marshalerType) { checkIsEmpty, err := createCheckIsEmpty(typ) diff --git a/feature_reflect_native.go b/feature_reflect_native.go index cf3ed51..a2ec95d 100644 --- a/feature_reflect_native.go +++ b/feature_reflect_native.go @@ -4,7 +4,6 @@ import ( "encoding" "encoding/base64" "encoding/json" - "reflect" "unsafe" ) @@ -425,7 +424,7 @@ func (codec *jsoniterRawMessageCodec) IsEmpty(ptr unsafe.Pointer) bool { } type base64Codec struct { - actualType reflect.Type + sliceDecoder ValDecoder } func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { @@ -436,21 +435,28 @@ func (codec *base64Codec) Decode(ptr unsafe.Pointer, iter *Iterator) { ptrSlice.Data = nil return } - encoding := base64.StdEncoding - src := iter.SkipAndReturnBytes() - src = src[1 : len(src)-1] - decodedLen := encoding.DecodedLen(len(src)) - dst := make([]byte, decodedLen) - len, err := encoding.Decode(dst, src) - if err != nil { - iter.ReportError("decode base64", err.Error()) - } else { - dst = dst[:len] - dstSlice := (*sliceHeader)(unsafe.Pointer(&dst)) - ptrSlice := (*sliceHeader)(ptr) - ptrSlice.Data = dstSlice.Data - ptrSlice.Cap = dstSlice.Cap - ptrSlice.Len = dstSlice.Len + switch iter.WhatIsNext() { + case String: + encoding := base64.StdEncoding + src := iter.SkipAndReturnBytes() + src = src[1 : len(src)-1] + decodedLen := encoding.DecodedLen(len(src)) + dst := make([]byte, decodedLen) + len, err := encoding.Decode(dst, src) + if err != nil { + iter.ReportError("decode base64", err.Error()) + } else { + dst = dst[:len] + dstSlice := (*sliceHeader)(unsafe.Pointer(&dst)) + ptrSlice := (*sliceHeader)(ptr) + ptrSlice.Data = dstSlice.Data + ptrSlice.Cap = dstSlice.Cap + ptrSlice.Len = dstSlice.Len + } + case Array: + codec.sliceDecoder.Decode(ptr, iter) + default: + iter.ReportError("base64Codec", "invalid input") } } diff --git a/jsoniter_array_test.go b/jsoniter_array_test.go index a6162b1..0f71ecb 100644 --- a/jsoniter_array_test.go +++ b/jsoniter_array_test.go @@ -156,7 +156,7 @@ func Test_encode_byte_array(t *testing.T) { should.Equal(`"AQID"`, string(bytes)) } -func Test_decode_byte_array(t *testing.T) { +func Test_decode_byte_array_from_base64(t *testing.T) { should := require.New(t) data := []byte{} err := json.Unmarshal([]byte(`"AQID"`), &data) @@ -167,6 +167,17 @@ func Test_decode_byte_array(t *testing.T) { should.Equal([]byte{1, 2, 3}, data) } +func Test_decode_byte_array_from_array(t *testing.T) { + should := require.New(t) + data := []byte{} + err := json.Unmarshal([]byte(`[1,2,3]`), &data) + should.Nil(err) + should.Equal([]byte{1, 2, 3}, data) + err = Unmarshal([]byte(`[1,2,3]`), &data) + should.Nil(err) + should.Equal([]byte{1, 2, 3}, data) +} + func Test_decode_slice(t *testing.T) { should := require.New(t) slice := make([]string, 0, 5) diff --git a/jsoniter_large_file_test.go b/jsoniter_large_file_test.go index 8d71885..29eb58b 100644 --- a/jsoniter_large_file_test.go +++ b/jsoniter_large_file_test.go @@ -122,7 +122,7 @@ func init() { /* 200000 8886 ns/op 4336 B/op 6 allocs/op 50000 34244 ns/op 6744 B/op 14 allocs/op - */ +*/ func Benchmark_jsoniter_large_file(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ {