nex-go/stream_in.go

330 lines
7.9 KiB
Go

package nex
import (
"errors"
"reflect"
"strings"
crunch "github.com/superwhiskers/crunch/v3"
)
// StreamIn is an input stream abstraction of github.com/superwhiskers/crunch with nex type support
type StreamIn struct {
*crunch.Buffer
Server *Server
}
// ReadBool reads a bool
func (stream *StreamIn) ReadBool() bool {
return (stream.ReadByteNext() == 1)
}
// ReadUInt8 reads a uint8
func (stream *StreamIn) ReadUInt8() uint8 {
return uint8(stream.ReadByteNext())
}
// ReadUInt16LE reads a uint16
func (stream *StreamIn) ReadUInt16LE() uint16 {
return stream.ReadU16LENext(1)[0]
}
// ReadUInt32LE reads a uint32
func (stream *StreamIn) ReadUInt32LE() uint32 {
return stream.ReadU32LENext(1)[0]
}
// ReadUInt32BE reads a uint32
func (stream *StreamIn) ReadUInt32BE() uint32 {
return stream.ReadU32BENext(1)[0]
}
// ReadInt32LE reads a int32
func (stream *StreamIn) ReadInt32LE() int32 {
return int32(stream.ReadU32LENext(1)[0])
}
// ReadUInt64LE reads a uint64
func (stream *StreamIn) ReadUInt64LE() uint64 {
return stream.ReadU64LENext(1)[0]
}
// ReadUInt64BE reads a uint64
func (stream *StreamIn) ReadUInt64BE() uint64 {
return stream.ReadU64BENext(1)[0]
}
// ReadString reads and returns a nex string type
func (stream *StreamIn) ReadString() (string, error) {
length := stream.ReadUInt16LE()
if len(stream.Bytes()[stream.ByteOffset():]) < int(length) {
return "", errors.New("[StreamIn] Nex string length longer than data size")
}
stringData := stream.ReadBytesNext(int64(length))
str := string(stringData)
return strings.TrimRight(str, "\x00"), nil
}
// ReadBuffer reads a nex Buffer type
func (stream *StreamIn) ReadBuffer() ([]byte, error) {
length := stream.ReadUInt32LE()
if len(stream.Bytes()[stream.ByteOffset():]) < int(length) {
return []byte{}, errors.New("[StreamIn] Nex buffer length longer than data size")
}
data := stream.ReadBytesNext(int64(length))
return data, nil
}
// ReadQBuffer reads a nex qBuffer type
func (stream *StreamIn) ReadQBuffer() ([]byte, error) {
length := stream.ReadUInt16LE()
if len(stream.Bytes()[stream.ByteOffset():]) < int(length) {
return []byte{}, errors.New("[StreamIn] Nex qBuffer length longer than data size")
}
data := stream.ReadBytesNext(int64(length))
return data, nil
}
// ReadStructure reads a nex Structure type
func (stream *StreamIn) ReadStructure(structure StructureInterface) (StructureInterface, error) {
if structure.ParentType() != nil {
_, err := stream.ReadStructure(structure.ParentType())
if err != nil {
return structure, errors.New("[ReadStructure] " + err.Error())
}
}
nexVersion := stream.Server.NEXVersion()
if nexVersion.Major >= 3 && nexVersion.Minor >= 5 {
// skip the new struct header as we don't really need the data there
_ = stream.ReadUInt8() // structure header version
_ = stream.ReadUInt32LE() // structure content length
}
err := structure.ExtractFromStream(stream)
if err != nil {
return structure, errors.New("[ReadStructure] " + err.Error())
}
return structure, nil
}
// ReadVariant reads a Variant type. This type can hold 7 different types
func (stream *StreamIn) ReadVariant() *Variant {
variant := NewVariant()
_ = variant.ExtractFromStream(stream)
return variant
}
// ReadMap reads a Map type with the given key and value types
func (stream *StreamIn) ReadMap(keyFunction interface{}, valueFunction interface{}) (map[interface{}]interface{}, error) {
/*
TODO: Make this not suck
Map types can have any type as the key and any type as the value
Due to strict typing we cannot just pass stream functions as these values and call them
At the moment this just reads what type you want from the interface{} function type
*/
length := stream.ReadUInt32LE()
newMap := make(map[interface{}]interface{})
for i := 0; i < int(length); i++ {
var key interface{}
var value interface{}
var err error
switch keyFunction.(type) {
case func() (string, error):
key, err = stream.ReadString()
}
if err != nil {
return nil, err
}
switch valueFunction.(type) {
case func() interface{}:
value = stream.ReadVariant()
}
newMap[key] = value
}
return newMap, nil
}
// ReadDateTime reads a DateTime type
func (stream *StreamIn) ReadDateTime() *DateTime {
return NewDateTime(stream.ReadUInt64LE())
}
// ReadDataHolder reads a DataHolder type
func (stream *StreamIn) ReadDataHolder() *DataHolder {
dataHolder := NewDataHolder()
err := dataHolder.ExtractFromStream(stream)
if err != nil {
// TODO - Make this maybe return an error?
logger.Error(err.Error())
}
return dataHolder
}
// ReadStationURL reads a StationURL type
func (stream *StreamIn) ReadStationURL() *StationURL {
stationString, err := stream.ReadString()
if err != nil {
// TODO - Make this maybe return an error?
logger.Error(err.Error())
}
return NewStationURL(stationString)
}
// ReadListUInt8 reads a list of uint8 types
func (stream *StreamIn) ReadListUInt8() []uint8 {
length := stream.ReadUInt32LE()
list := make([]uint8, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadUInt8()
list = append(list, value)
}
return list
}
// ReadListUInt16LE reads a list of uint16 types
func (stream *StreamIn) ReadListUInt16LE() []uint16 {
length := stream.ReadUInt32LE()
list := make([]uint16, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadUInt16LE()
list = append(list, value)
}
return list
}
// ReadListUInt32LE reads a list of uint32 types
func (stream *StreamIn) ReadListUInt32LE() []uint32 {
length := stream.ReadUInt32LE()
list := make([]uint32, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadUInt32LE()
list = append(list, value)
}
return list
}
// ReadListInt32LE reads a list of int32 types
func (stream *StreamIn) ReadListInt32LE() []int32 {
length := stream.ReadUInt32LE()
list := make([]int32, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadInt32LE()
list = append(list, value)
}
return list
}
// ReadListUInt64LE reads a list of uint64 types
func (stream *StreamIn) ReadListUInt64LE() []uint64 {
length := stream.ReadUInt32LE()
list := make([]uint64, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadUInt64LE()
list = append(list, value)
}
return list
}
// ReadListString reads a list of NEX String types
func (stream *StreamIn) ReadListString() []string {
length := stream.ReadUInt32LE()
list := make([]string, 0, length)
for i := 0; i < int(length); i++ {
value, _ := stream.ReadString()
list = append(list, value)
}
return list
}
// ReadListQBuffer reads a list of NEX QBuffer types
func (stream *StreamIn) ReadListQBuffer() [][]byte {
length := stream.ReadUInt32LE()
list := make([][]byte, 0, length)
for i := 0; i < int(length); i++ {
value, _ := stream.ReadQBuffer()
list = append(list, value)
}
return list
}
// ReadListStationURL reads a list of NEX Station URL types
func (stream *StreamIn) ReadListStationURL() []*StationURL {
length := stream.ReadUInt32LE()
list := make([]*StationURL, 0, length)
for i := 0; i < int(length); i++ {
value := stream.ReadStationURL()
list = append(list, value)
}
return list
}
// ReadListStructure reads and returns a list structure types
func (stream *StreamIn) ReadListStructure(structure StructureInterface) (interface{}, error) {
length := stream.ReadUInt32LE()
structureType := reflect.TypeOf(structure)
structureSlice := reflect.MakeSlice(reflect.SliceOf(structureType), 0, int(length))
for i := 0; i < int(length); i++ {
newStructure := reflect.New(reflect.TypeOf(structure).Elem()).Interface().(StructureInterface)
extractedStructure, err := stream.ReadStructure(newStructure)
if err != nil {
return nil, err
}
structureSlice = reflect.Append(structureSlice, reflect.ValueOf(extractedStructure))
}
return structureSlice.Interface(), nil
}
// NewStreamIn returns a new NEX input stream
func NewStreamIn(data []byte, server *Server) *StreamIn {
return &StreamIn{
Buffer: crunch.NewBuffer(data),
Server: server,
}
}