2018-02-04 19:54:51 +00:00
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
2018-03-17 11:53:21 +00:00
|
|
|
"bytes"
|
2018-02-04 19:54:51 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Variable length integer, can be encoded to save space according to the value typed.
|
|
|
|
// len 1 uint8
|
|
|
|
// len 3 0xfd + uint16
|
|
|
|
// len 5 0xfe = uint32
|
|
|
|
// len 9 0xff = uint64
|
|
|
|
// For more information about this:
|
|
|
|
// https://github.com/neo-project/neo/wiki/Network-Protocol
|
|
|
|
|
|
|
|
// ReadVarUint reads a variable unsigned integer and returns it as a uint64.
|
|
|
|
func ReadVarUint(r io.Reader) uint64 {
|
|
|
|
var b uint8
|
|
|
|
binary.Read(r, binary.LittleEndian, &b)
|
2018-11-26 15:56:45 +00:00
|
|
|
switch b {
|
|
|
|
case 0xfd:
|
2018-02-04 19:54:51 +00:00
|
|
|
var v uint16
|
|
|
|
binary.Read(r, binary.LittleEndian, &v)
|
|
|
|
return uint64(v)
|
2018-11-26 15:56:45 +00:00
|
|
|
case 0xfe:
|
2018-02-04 19:54:51 +00:00
|
|
|
var v uint32
|
|
|
|
binary.Read(r, binary.LittleEndian, &v)
|
|
|
|
return uint64(v)
|
2018-11-26 15:56:45 +00:00
|
|
|
case 0xff:
|
2018-02-04 19:54:51 +00:00
|
|
|
var v uint64
|
|
|
|
binary.Read(r, binary.LittleEndian, &v)
|
|
|
|
return v
|
2018-11-26 15:56:45 +00:00
|
|
|
default:
|
|
|
|
return uint64(b)
|
2018-02-04 19:54:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteVarUint writes a variable unsigned integer.
|
|
|
|
func WriteVarUint(w io.Writer, val uint64) error {
|
|
|
|
if val < 0 {
|
|
|
|
return errors.New("value out of range")
|
|
|
|
}
|
|
|
|
if val < 0xfd {
|
2018-11-26 15:56:45 +00:00
|
|
|
return binary.Write(w, binary.LittleEndian, uint8(val))
|
2018-02-04 19:54:51 +00:00
|
|
|
}
|
|
|
|
if val < 0xFFFF {
|
2018-11-26 15:56:45 +00:00
|
|
|
if err := binary.Write(w, binary.LittleEndian, byte(0xfd)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return binary.Write(w, binary.LittleEndian, uint16(val))
|
2018-02-04 19:54:51 +00:00
|
|
|
}
|
|
|
|
if val < 0xFFFFFFFF {
|
2018-11-26 15:56:45 +00:00
|
|
|
if err := binary.Write(w, binary.LittleEndian, byte(0xfe)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return binary.Write(w, binary.LittleEndian, uint32(val))
|
2018-02-04 19:54:51 +00:00
|
|
|
}
|
|
|
|
|
2018-11-26 15:56:45 +00:00
|
|
|
if err := binary.Write(w, binary.LittleEndian, byte(0xff)); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-02-04 19:54:51 +00:00
|
|
|
|
2018-11-26 15:56:45 +00:00
|
|
|
return binary.Write(w, binary.LittleEndian, val)
|
2018-02-04 19:54:51 +00:00
|
|
|
}
|
2018-03-17 11:53:21 +00:00
|
|
|
|
2018-03-25 10:45:54 +00:00
|
|
|
// ReadVarBytes reads a variable length byte array.
|
|
|
|
func ReadVarBytes(r io.Reader) ([]byte, error) {
|
|
|
|
n := ReadVarUint(r)
|
|
|
|
b := make([]byte, n)
|
|
|
|
if err := binary.Read(r, binary.LittleEndian, b); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadVarString reads a variable length string.
|
|
|
|
func ReadVarString(r io.Reader) (string, error) {
|
|
|
|
b, err := ReadVarBytes(r)
|
|
|
|
return string(b), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteVarString writes a variable length string.
|
|
|
|
func WriteVarString(w io.Writer, s string) error {
|
|
|
|
return WriteVarBytes(w, []byte(s))
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteVarBytes writes a variable length byte array.
|
|
|
|
func WriteVarBytes(w io.Writer, b []byte) error {
|
|
|
|
if err := WriteVarUint(w, uint64(len(b))); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return binary.Write(w, binary.LittleEndian, b)
|
|
|
|
}
|
|
|
|
|
2018-03-17 11:53:21 +00:00
|
|
|
// Read2000Uint256Hashes attempt to read 2000 Uint256 hashes from
|
|
|
|
// the given byte array.
|
|
|
|
func Read2000Uint256Hashes(b []byte) ([]Uint256, error) {
|
|
|
|
r := bytes.NewReader(b)
|
|
|
|
lenHashes := ReadVarUint(r)
|
|
|
|
hashes := make([]Uint256, lenHashes)
|
|
|
|
if err := binary.Read(r, binary.LittleEndian, hashes); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return hashes, nil
|
|
|
|
}
|