package binary import ( "encoding/hex" "errors" "math/big" "strings" "github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/encoding/bigint" ) var ( // ErrInvalidBase is returned when base is invalid. ErrInvalidBase = errors.New("invalid base") // ErrInvalidFormat is returned when string is not a number. ErrInvalidFormat = errors.New("invalid format") ) // Itoa converts number to string. func Itoa(ic *interop.Context) error { num := ic.VM.Estack().Pop().BigInt() base := ic.VM.Estack().Pop().BigInt() if !base.IsInt64() { return ErrInvalidBase } var s string switch b := base.Int64(); b { case 10: s = num.Text(10) case 16: if num.Sign() == 0 { s = "0" break } bs := bigint.ToBytes(num) reverse(bs) s = hex.EncodeToString(bs) if pad := bs[0] & 0xF8; pad == 0 || pad == 0xF8 { s = s[1:] } s = strings.ToUpper(s) default: return ErrInvalidBase } ic.VM.Estack().PushVal(s) return nil } // Atoi converts string to number. func Atoi(ic *interop.Context) error { num := ic.VM.Estack().Pop().String() base := ic.VM.Estack().Pop().BigInt() if !base.IsInt64() { return ErrInvalidBase } var bi *big.Int switch b := base.Int64(); b { case 10: var ok bool bi, ok = new(big.Int).SetString(num, int(b)) if !ok { return ErrInvalidFormat } case 16: changed := len(num)%2 != 0 if changed { num = "0" + num } bs, err := hex.DecodeString(num) if err != nil { return ErrInvalidFormat } if changed && bs[0]&0x8 != 0 { bs[0] |= 0xF0 } reverse(bs) bi = bigint.FromBytes(bs) default: return ErrInvalidBase } ic.VM.Estack().PushVal(bi) return nil } func reverse(b []byte) { l := len(b) for i := 0; i < l/2; i++ { b[i], b[l-i-1] = b[l-i-1], b[i] } }