forked from chanxuehong/wechat
/
hack.go
131 lines (117 loc) · 3.03 KB
/
hack.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"encoding/json"
"reflect"
"strconv"
)
var jsonNumberType = reflect.TypeOf(json.Number(""))
var trueLiteral = []byte("true")
var falseLiteral = []byte("false")
func unmarshalStringToNumberOrBoolean(d *decodeState, s []byte, v reflect.Value, fromQuoted bool) {
if fromQuoted {
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
return
}
switch {
default:
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
case isValidNumberBytes(s):
switch v.Kind() {
default:
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
s := string(s)
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || v.OverflowInt(n) {
d.saveError(&UnmarshalTypeError{"string " + s, v.Type(), int64(d.off)})
break
}
v.SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
s := string(s)
n, err := strconv.ParseUint(s, 10, 64)
if err != nil || v.OverflowUint(n) {
d.saveError(&UnmarshalTypeError{"string " + s, v.Type(), int64(d.off)})
break
}
v.SetUint(n)
case reflect.Float32, reflect.Float64:
s := string(s)
n, err := strconv.ParseFloat(s, v.Type().Bits())
if err != nil || v.OverflowFloat(n) {
d.saveError(&UnmarshalTypeError{"string " + s, v.Type(), int64(d.off)})
break
}
v.SetFloat(n)
}
case bytes.Equal(s, trueLiteral):
switch v.Kind() {
default:
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
case reflect.Bool:
v.SetBool(true)
}
case bytes.Equal(s, falseLiteral):
switch v.Kind() {
default:
d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
case reflect.Bool:
v.SetBool(false)
}
}
}
// isValidNumberBytes reports whether s is a valid JSON number literal.
func isValidNumberBytes(s []byte) bool {
// This function implements the JSON numbers grammar.
// See https://tools.ietf.org/html/rfc7159#section-6
// and http://json.org/number.gif
if len(s) == 0 {
return false
}
// Optional -
if s[0] == '-' {
s = s[1:]
if len(s) == 0 {
return false
}
}
// Digits
switch {
default:
return false
case s[0] == '0':
s = s[1:]
case '1' <= s[0] && s[0] <= '9':
s = s[1:]
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
}
}
// . followed by 1 or more digits.
if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
s = s[2:]
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
}
}
// e or E followed by an optional - or + and
// 1 or more digits.
if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
s = s[1:]
if s[0] == '+' || s[0] == '-' {
s = s[1:]
if len(s) == 0 {
return false
}
}
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
s = s[1:]
}
}
// Make sure we are at the end.
return len(s) == 0
}