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] } // ReadInt64LE reads a int64 func (stream *StreamIn) ReadInt64LE() int64 { return int64(stream.ReadU64LENext(1)[0]) } // ReadUInt64BE reads a uint64 func (stream *StreamIn) ReadUInt64BE() uint64 { return stream.ReadU64BENext(1)[0] } // ReadFloat64LE reads a int64 func (stream *StreamIn) ReadFloat64LE() float64 { return stream.ReadF64LENext(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() *Variant: 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 := structure.Copy() 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, } }