github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/common/hexutil/json.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package hexutil 13 14 import ( 15 "encoding/hex" 16 "encoding/json" 17 "fmt" 18 "math/big" 19 "reflect" 20 "strconv" 21 ) 22 23 var ( 24 bytesT = reflect.TypeOf(Bytes(nil)) 25 bigT = reflect.TypeOf((*Big)(nil)) 26 uintT = reflect.TypeOf(Uint(0)) 27 uint64T = reflect.TypeOf(Uint64(0)) 28 ) 29 30 // Bytes marshals/unmarshals as a JSON string with 0x prefix. 31 // The empty slice marshals as "0x". 32 type Bytes []byte 33 34 // MarshalText implements encoding.TextMarshaler 35 func (b Bytes) MarshalText() ([]byte, error) { 36 result := make([]byte, len(b)*2+2) 37 copy(result, `0x`) 38 hex.Encode(result[2:], b) 39 return result, nil 40 } 41 42 // UnmarshalJSON implements json.Unmarshaler. 43 func (b *Bytes) UnmarshalJSON(input []byte) error { 44 if !isString(input) { 45 return errNonString(bytesT) 46 } 47 return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bytesT) 48 } 49 50 // UnmarshalText implements encoding.TextUnmarshaler. 51 func (b *Bytes) UnmarshalText(input []byte) error { 52 raw, err := checkText(input, true) 53 if err != nil { 54 return err 55 } 56 dec := make([]byte, len(raw)/2) 57 if _, err = hex.Decode(dec, raw); err != nil { 58 err = mapError(err) 59 } else { 60 *b = dec 61 } 62 return err 63 } 64 65 // String returns the hex encoding of b. 66 func (b Bytes) String() string { 67 return Encode(b) 68 } 69 70 // UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out 71 // determines the required input length. This function is commonly used to implement the 72 // UnmarshalJSON method for fixed-size types. 73 func UnmarshalFixedJSON(typ reflect.Type, input, out []byte) error { 74 if !isString(input) { 75 return errNonString(typ) 76 } 77 return wrapTypeError(UnmarshalFixedText(typ.String(), input[1:len(input)-1], out), typ) 78 } 79 80 // UnmarshalFixedText decodes the input as a string with 0x prefix. The length of out 81 // determines the required input length. This function is commonly used to implement the 82 // UnmarshalText method for fixed-size types. 83 func UnmarshalFixedText(typname string, input, out []byte) error { 84 raw, err := checkText(input, true) 85 if err != nil { 86 return err 87 } 88 if len(raw)/2 != len(out) { 89 return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname) 90 } 91 // Pre-verify syntax before modifying out. 92 for _, b := range raw { 93 if decodeNibble(b) == badNibble { 94 return ErrSyntax 95 } 96 } 97 hex.Decode(out, raw) 98 return nil 99 } 100 101 // UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The 102 // length of out determines the required input length. This function is commonly used to 103 // implement the UnmarshalText method for fixed-size types. 104 func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error { 105 raw, err := checkText(input, false) 106 if err != nil { 107 return err 108 } 109 if len(raw)/2 != len(out) { 110 return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname) 111 } 112 // Pre-verify syntax before modifying out. 113 for _, b := range raw { 114 if decodeNibble(b) == badNibble { 115 return ErrSyntax 116 } 117 } 118 hex.Decode(out, raw) 119 return nil 120 } 121 122 // Big marshals/unmarshals as a JSON string with 0x prefix. 123 // The zero value marshals as "0x0". 124 // 125 // Negative integers are not supported at this time. Attempting to marshal them will 126 // return an error. Values larger than 256bits are rejected by Unmarshal but will be 127 // marshaled without error. 128 type Big big.Int 129 130 // MarshalText implements encoding.TextMarshaler 131 func (b Big) MarshalText() ([]byte, error) { 132 return []byte(EncodeBig((*big.Int)(&b))), nil 133 } 134 135 // UnmarshalJSON implements json.Unmarshaler. 136 func (b *Big) UnmarshalJSON(input []byte) error { 137 if !isString(input) { 138 return errNonString(bigT) 139 } 140 return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bigT) 141 } 142 143 // UnmarshalText implements encoding.TextUnmarshaler 144 func (b *Big) UnmarshalText(input []byte) error { 145 raw, err := checkNumberText(input) 146 if err != nil { 147 return err 148 } 149 if len(raw) > 64 { 150 return ErrBig256Range 151 } 152 words := make([]big.Word, len(raw)/bigWordNibbles+1) 153 end := len(raw) 154 for i := range words { 155 start := end - bigWordNibbles 156 if start < 0 { 157 start = 0 158 } 159 for ri := start; ri < end; ri++ { 160 nib := decodeNibble(raw[ri]) 161 if nib == badNibble { 162 return ErrSyntax 163 } 164 words[i] *= 16 165 words[i] += big.Word(nib) 166 } 167 end = start 168 } 169 var dec big.Int 170 dec.SetBits(words) 171 *b = (Big)(dec) 172 return nil 173 } 174 175 // ToInt converts b to a big.Int. 176 func (b *Big) ToInt() *big.Int { 177 return (*big.Int)(b) 178 } 179 180 // String returns the hex encoding of b. 181 func (b *Big) String() string { 182 return EncodeBig(b.ToInt()) 183 } 184 185 // Uint64 marshals/unmarshals as a JSON string with 0x prefix. 186 // The zero value marshals as "0x0". 187 type Uint64 uint64 188 189 // MarshalText implements encoding.TextMarshaler. 190 func (b Uint64) MarshalText() ([]byte, error) { 191 buf := make([]byte, 2, 10) 192 copy(buf, `0x`) 193 buf = strconv.AppendUint(buf, uint64(b), 16) 194 return buf, nil 195 } 196 197 // UnmarshalJSON implements json.Unmarshaler. 198 func (b *Uint64) UnmarshalJSON(input []byte) error { 199 if !isString(input) { 200 return errNonString(uint64T) 201 } 202 return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uint64T) 203 } 204 205 // UnmarshalText implements encoding.TextUnmarshaler 206 func (b *Uint64) UnmarshalText(input []byte) error { 207 raw, err := checkNumberText(input) 208 if err != nil { 209 return err 210 } 211 if len(raw) > 16 { 212 return ErrUint64Range 213 } 214 var dec uint64 215 for _, byte := range raw { 216 nib := decodeNibble(byte) 217 if nib == badNibble { 218 return ErrSyntax 219 } 220 dec *= 16 221 dec += nib 222 } 223 *b = Uint64(dec) 224 return nil 225 } 226 227 // String returns the hex encoding of b. 228 func (b Uint64) String() string { 229 return EncodeUint64(uint64(b)) 230 } 231 232 // Uint marshals/unmarshals as a JSON string with 0x prefix. 233 // The zero value marshals as "0x0". 234 type Uint uint 235 236 // MarshalText implements encoding.TextMarshaler. 237 func (b Uint) MarshalText() ([]byte, error) { 238 return Uint64(b).MarshalText() 239 } 240 241 // UnmarshalJSON implements json.Unmarshaler. 242 func (b *Uint) UnmarshalJSON(input []byte) error { 243 if !isString(input) { 244 return errNonString(uintT) 245 } 246 return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uintT) 247 } 248 249 // UnmarshalText implements encoding.TextUnmarshaler. 250 func (b *Uint) UnmarshalText(input []byte) error { 251 var u64 Uint64 252 err := u64.UnmarshalText(input) 253 if u64 > Uint64(^uint(0)) || err == ErrUint64Range { 254 return ErrUintRange 255 } else if err != nil { 256 return err 257 } 258 *b = Uint(u64) 259 return nil 260 } 261 262 // String returns the hex encoding of b. 263 func (b Uint) String() string { 264 return EncodeUint64(uint64(b)) 265 } 266 267 func isString(input []byte) bool { 268 return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' 269 } 270 271 func bytesHave0xPrefix(input []byte) bool { 272 return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') 273 } 274 275 func checkText(input []byte, wantPrefix bool) ([]byte, error) { 276 if len(input) == 0 { 277 return nil, nil // empty strings are allowed 278 } 279 if bytesHave0xPrefix(input) { 280 input = input[2:] 281 } else if wantPrefix { 282 return nil, ErrMissingPrefix 283 } 284 if len(input)%2 != 0 { 285 return nil, ErrOddLength 286 } 287 return input, nil 288 } 289 290 func checkNumberText(input []byte) (raw []byte, err error) { 291 if len(input) == 0 { 292 return nil, nil // empty strings are allowed 293 } 294 if !bytesHave0xPrefix(input) { 295 return nil, ErrMissingPrefix 296 } 297 input = input[2:] 298 if len(input) == 0 { 299 return nil, ErrEmptyNumber 300 } 301 if len(input) > 1 && input[0] == '0' { 302 return nil, ErrLeadingZero 303 } 304 return input, nil 305 } 306 307 func wrapTypeError(err error, typ reflect.Type) error { 308 if _, ok := err.(*decError); ok { 309 return &json.UnmarshalTypeError{Value: err.Error(), Type: typ} 310 } 311 return err 312 } 313 314 func errNonString(typ reflect.Type) error { 315 return &json.UnmarshalTypeError{Value: "non-string", Type: typ} 316 }