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