forked from shamaton/msgpack
/
decode.go
75 lines (62 loc) · 1.98 KB
/
decode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package time
import (
"encoding/binary"
"fmt"
"reflect"
"time"
"github.com/shamaton/msgpack/def"
"github.com/shamaton/msgpack/ext"
)
var zero = time.Unix(0, 0)
var Decoder = new(timeDecoder)
type timeDecoder struct {
ext.DecoderCommon
}
func (td *timeDecoder) Code() int8 {
return def.TimeStamp
}
func (td *timeDecoder) IsType(offset int, d *[]byte) bool {
code, offset := td.ReadSize1(offset, d)
if code == def.Fixext4 {
t, _ := td.ReadSize1(offset, d)
return int8(t) == td.Code()
} else if code == def.Fixext8 {
t, _ := td.ReadSize1(offset, d)
return int8(t) == td.Code()
} else if code == def.Ext8 {
l, offset := td.ReadSize1(offset, d)
t, _ := td.ReadSize1(offset, d)
return l == 12 && int8(t) == td.Code()
}
return false
}
func (td *timeDecoder) AsValue(offset int, k reflect.Kind, d *[]byte) (interface{}, int, error) {
code, offset := td.ReadSize1(offset, d)
switch code {
case def.Fixext4:
_, offset = td.ReadSize1(offset, d)
bs, offset := td.ReadSize4(offset, d)
return time.Unix(int64(binary.BigEndian.Uint32(bs)), 0), offset, nil
case def.Fixext8:
_, offset = td.ReadSize1(offset, d)
bs, offset := td.ReadSize8(offset, d)
data64 := binary.BigEndian.Uint64(bs)
nano := int64(data64 >> 34)
if nano > 999999999 {
return zero, 0, fmt.Errorf("In timestamp 64 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
return time.Unix(int64(data64&0x00000003ffffffff), nano), offset, nil
case def.Ext8:
_, offset = td.ReadSize1(offset, d)
_, offset = td.ReadSize1(offset, d)
nanobs, offset := td.ReadSize4(offset, d)
secbs, offset := td.ReadSize8(offset, d)
nano := binary.BigEndian.Uint32(nanobs)
if nano > 999999999 {
return zero, 0, fmt.Errorf("In timestamp 96 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
sec := binary.BigEndian.Uint64(secbs)
return time.Unix(int64(sec), int64(nano)), offset, nil
}
return zero, 0, fmt.Errorf("should not reach this line!! code %x decoding %v", code, k)
}