161 lines
3.0 KiB
Go
161 lines
3.0 KiB
Go
package protocol
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"math"
|
|
)
|
|
|
|
type UxReader struct {
|
|
data []byte
|
|
pos int
|
|
}
|
|
|
|
func NewUxReader(data []byte) *UxReader {
|
|
return &UxReader{data: data, pos: 0}
|
|
}
|
|
|
|
func (r *UxReader) Position() int { return r.pos }
|
|
func (r *UxReader) Remaining() int { return len(r.data) - r.pos }
|
|
|
|
func (r *UxReader) U8() (byte, error) {
|
|
if r.pos >= len(r.data) {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
b := r.data[r.pos]
|
|
r.pos++
|
|
return b, nil
|
|
}
|
|
|
|
func (r *UxReader) Bool() (bool, error) {
|
|
b, err := r.U8()
|
|
return b != 0, err
|
|
}
|
|
|
|
func (r *UxReader) I16() (int16, error) {
|
|
if r.Remaining() < 2 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := int16(binary.LittleEndian.Uint16(r.data[r.pos : r.pos+2]))
|
|
r.pos += 2
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) U16() (uint16, error) {
|
|
if r.Remaining() < 2 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := binary.LittleEndian.Uint16(r.data[r.pos : r.pos+2])
|
|
r.pos += 2
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) I32() (int32, error) {
|
|
if r.Remaining() < 4 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := int32(binary.LittleEndian.Uint32(r.data[r.pos : r.pos+4]))
|
|
r.pos += 4
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) U32() (uint32, error) {
|
|
if r.Remaining() < 4 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := binary.LittleEndian.Uint32(r.data[r.pos : r.pos+4])
|
|
r.pos += 4
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) I64() (int64, error) {
|
|
if r.Remaining() < 8 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := int64(binary.LittleEndian.Uint64(r.data[r.pos : r.pos+8]))
|
|
r.pos += 8
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) U64() (ulong uint64, err error) {
|
|
if r.Remaining() < 8 {
|
|
return 0, errors.New("EOF")
|
|
}
|
|
v := binary.LittleEndian.Uint64(r.data[r.pos : r.pos+8])
|
|
r.pos += 8
|
|
return v, nil
|
|
}
|
|
|
|
func (r *UxReader) F32() (float32, error) {
|
|
bits, err := r.U32()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return math.Float32frombits(bits), nil
|
|
}
|
|
|
|
func (r *UxReader) F64() (float64, error) {
|
|
bits, err := r.U64()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return math.Float64frombits(bits), nil
|
|
}
|
|
|
|
func (r *UxReader) ReadVarInt() (int, error) {
|
|
shift := 0
|
|
result := 0
|
|
for r.pos < len(r.data) {
|
|
b := r.data[r.pos]
|
|
r.pos++
|
|
result |= int(b&0x7F) << shift
|
|
if (b & 0x80) == 0 {
|
|
return result, nil
|
|
}
|
|
shift += 7
|
|
}
|
|
return result, errors.New("unterminated varint")
|
|
}
|
|
|
|
func (r *UxReader) Int7() (int, error) {
|
|
v, err := r.ReadVarInt()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if v < 1 {
|
|
return 0, nil
|
|
}
|
|
return v - 1, nil
|
|
}
|
|
|
|
func (r *UxReader) Raw7() (int, error) {
|
|
return r.ReadVarInt()
|
|
}
|
|
|
|
func (r *UxReader) UxString() (string, error) {
|
|
lenPlus, err := r.ReadVarInt()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if lenPlus == 0 {
|
|
return "", nil
|
|
}
|
|
length := lenPlus - 1
|
|
if length > r.Remaining() {
|
|
return "", errors.New("string length exceeds buffer")
|
|
}
|
|
str := string(r.data[r.pos : r.pos+length])
|
|
r.pos += length
|
|
return str, nil
|
|
}
|
|
|
|
func (r *UxReader) Bytes(count int) ([]byte, error) {
|
|
if count < 0 || count > r.Remaining() {
|
|
return nil, errors.New("requested count exceeds buffer")
|
|
}
|
|
res := make([]byte, count)
|
|
copy(res, r.data[r.pos:r.pos+count])
|
|
r.pos += count
|
|
return res, nil
|
|
}
|