123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- // Copyright 2016 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package hexutil
- import (
- "encoding/hex"
- "encoding/json"
- "fmt"
- "math/big"
- "reflect"
- "strconv"
- )
- var (
- bytesT = reflect.TypeOf(Bytes(nil))
- bigT = reflect.TypeOf((*Big)(nil))
- uintT = reflect.TypeOf(Uint(0))
- uint64T = reflect.TypeOf(Uint64(0))
- )
- // Bytes marshals/unmarshals as a JSON string with 0x prefix.
- // The empty slice marshals as "0x".
- type Bytes []byte
- // MarshalText implements encoding.TextMarshaler
- func (b Bytes) MarshalText() ([]byte, error) {
- result := make([]byte, len(b)*2+2)
- copy(result, `0x`)
- hex.Encode(result[2:], b)
- return result, nil
- }
- // UnmarshalJSON implements json.Unmarshaler.
- func (b *Bytes) UnmarshalJSON(input []byte) error {
- if !isString(input) {
- return errNonString(bytesT)
- }
- return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bytesT)
- }
- // UnmarshalText implements encoding.TextUnmarshaler.
- func (b *Bytes) UnmarshalText(input []byte) error {
- raw, err := checkText(input, true)
- if err != nil {
- return err
- }
- dec := make([]byte, len(raw)/2)
- if _, err = hex.Decode(dec, raw); err != nil {
- err = mapError(err)
- } else {
- *b = dec
- }
- return err
- }
- // String returns the hex encoding of b.
- func (b Bytes) String() string {
- return Encode(b)
- }
- // UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length of out
- // determines the required input length. This function is commonly used to implement the
- // UnmarshalJSON method for fixed-size types.
- func UnmarshalFixedJSON(typ reflect.Type, input, out []byte) error {
- if !isString(input) {
- return errNonString(typ)
- }
- return wrapTypeError(UnmarshalFixedText(typ.String(), input[1:len(input)-1], out), typ)
- }
- // UnmarshalFixedText decodes the input as a string with 0x prefix. The length of out
- // determines the required input length. This function is commonly used to implement the
- // UnmarshalText method for fixed-size types.
- func UnmarshalFixedText(typname string, input, out []byte) error {
- raw, err := checkText(input, true)
- if err != nil {
- return err
- }
- if len(raw)/2 != len(out) {
- return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
- }
- // Pre-verify syntax before modifying out.
- for _, b := range raw {
- if decodeNibble(b) == badNibble {
- return ErrSyntax
- }
- }
- hex.Decode(out, raw)
- return nil
- }
- // UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The
- // length of out determines the required input length. This function is commonly used to
- // implement the UnmarshalText method for fixed-size types.
- func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error {
- raw, err := checkText(input, false)
- if err != nil {
- return err
- }
- if len(raw)/2 != len(out) {
- return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
- }
- // Pre-verify syntax before modifying out.
- for _, b := range raw {
- if decodeNibble(b) == badNibble {
- return ErrSyntax
- }
- }
- hex.Decode(out, raw)
- return nil
- }
- // Big marshals/unmarshals as a JSON string with 0x prefix.
- // The zero value marshals as "0x0".
- //
- // Negative integers are not supported at this time. Attempting to marshal them will
- // return an error. Values larger than 256bits are rejected by Unmarshal but will be
- // marshaled without error.
- type Big big.Int
- // MarshalText implements encoding.TextMarshaler
- func (b Big) MarshalText() ([]byte, error) {
- return []byte(EncodeBig((*big.Int)(&b))), nil
- }
- // UnmarshalJSON implements json.Unmarshaler.
- func (b *Big) UnmarshalJSON(input []byte) error {
- if !isString(input) {
- return errNonString(bigT)
- }
- return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), bigT)
- }
- // UnmarshalText implements encoding.TextUnmarshaler
- func (b *Big) UnmarshalText(input []byte) error {
- raw, err := checkNumberText(input)
- if err != nil {
- return err
- }
- if len(raw) > 64 {
- return ErrBig256Range
- }
- words := make([]big.Word, len(raw)/bigWordNibbles+1)
- end := len(raw)
- for i := range words {
- start := end - bigWordNibbles
- if start < 0 {
- start = 0
- }
- for ri := start; ri < end; ri++ {
- nib := decodeNibble(raw[ri])
- if nib == badNibble {
- return ErrSyntax
- }
- words[i] *= 16
- words[i] += big.Word(nib)
- }
- end = start
- }
- var dec big.Int
- dec.SetBits(words)
- *b = (Big)(dec)
- return nil
- }
- // ToInt converts b to a big.Int.
- func (b *Big) ToInt() *big.Int {
- return (*big.Int)(b)
- }
- // String returns the hex encoding of b.
- func (b *Big) String() string {
- return EncodeBig(b.ToInt())
- }
- // Uint64 marshals/unmarshals as a JSON string with 0x prefix.
- // The zero value marshals as "0x0".
- type Uint64 uint64
- // MarshalText implements encoding.TextMarshaler.
- func (b Uint64) MarshalText() ([]byte, error) {
- buf := make([]byte, 2, 10)
- copy(buf, `0x`)
- buf = strconv.AppendUint(buf, uint64(b), 16)
- return buf, nil
- }
- // UnmarshalJSON implements json.Unmarshaler.
- func (b *Uint64) UnmarshalJSON(input []byte) error {
- if !isString(input) {
- return errNonString(uint64T)
- }
- return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uint64T)
- }
- // UnmarshalText implements encoding.TextUnmarshaler
- func (b *Uint64) UnmarshalText(input []byte) error {
- raw, err := checkNumberText(input)
- if err != nil {
- return err
- }
- if len(raw) > 16 {
- return ErrUint64Range
- }
- var dec uint64
- for _, byte := range raw {
- nib := decodeNibble(byte)
- if nib == badNibble {
- return ErrSyntax
- }
- dec *= 16
- dec += nib
- }
- *b = Uint64(dec)
- return nil
- }
- // String returns the hex encoding of b.
- func (b Uint64) String() string {
- return EncodeUint64(uint64(b))
- }
- // Uint marshals/unmarshals as a JSON string with 0x prefix.
- // The zero value marshals as "0x0".
- type Uint uint
- // MarshalText implements encoding.TextMarshaler.
- func (b Uint) MarshalText() ([]byte, error) {
- return Uint64(b).MarshalText()
- }
- // UnmarshalJSON implements json.Unmarshaler.
- func (b *Uint) UnmarshalJSON(input []byte) error {
- if !isString(input) {
- return errNonString(uintT)
- }
- return wrapTypeError(b.UnmarshalText(input[1:len(input)-1]), uintT)
- }
- // UnmarshalText implements encoding.TextUnmarshaler.
- func (b *Uint) UnmarshalText(input []byte) error {
- var u64 Uint64
- err := u64.UnmarshalText(input)
- if u64 > Uint64(^uint(0)) || err == ErrUint64Range {
- return ErrUintRange
- } else if err != nil {
- return err
- }
- *b = Uint(u64)
- return nil
- }
- // String returns the hex encoding of b.
- func (b Uint) String() string {
- return EncodeUint64(uint64(b))
- }
- func isString(input []byte) bool {
- return len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"'
- }
- func bytesHave0xPrefix(input []byte) bool {
- return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
- }
- func checkText(input []byte, wantPrefix bool) ([]byte, error) {
- if len(input) == 0 {
- return nil, nil // empty strings are allowed
- }
- if bytesHave0xPrefix(input) {
- input = input[2:]
- } else if wantPrefix {
- return nil, ErrMissingPrefix
- }
- if len(input)%2 != 0 {
- return nil, ErrOddLength
- }
- return input, nil
- }
- func checkNumberText(input []byte) (raw []byte, err error) {
- if len(input) == 0 {
- return nil, nil // empty strings are allowed
- }
- if !bytesHave0xPrefix(input) {
- return nil, ErrMissingPrefix
- }
- input = input[2:]
- if len(input) == 0 {
- return nil, ErrEmptyNumber
- }
- if len(input) > 1 && input[0] == '0' {
- return nil, ErrLeadingZero
- }
- return input, nil
- }
- func wrapTypeError(err error, typ reflect.Type) error {
- if _, ok := err.(*decError); ok {
- return &json.UnmarshalTypeError{Value: err.Error(), Type: typ}
- }
- return err
- }
- func errNonString(typ reflect.Type) error {
- return &json.UnmarshalTypeError{Value: "non-string", Type: typ}
- }
|