mirror of
https://github.com/PretendoNetwork/nex-go.git
synced 2025-04-02 11:02:14 -04:00
330 lines
7.9 KiB
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,
|
|
}
|
|
}
|