github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/common/hexutil/json.go (about)

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