aim-oscar-server/tlv.go

115 lines
2.3 KiB
Go
Raw Normal View History

package main
import (
"encoding"
"encoding/binary"
"fmt"
"io"
"github.com/pkg/errors"
)
var _ encoding.BinaryUnmarshaler = &TLV{}
var _ encoding.BinaryMarshaler = &TLV{}
type TLV struct {
Type uint16
DataLength uint16
Data []byte
}
func NewTLV(tlvType uint16, data []byte) *TLV {
return &TLV{
Type: tlvType,
DataLength: uint16(len(data)),
Data: data,
}
}
func (t *TLV) Len() int {
return 4 + int(t.DataLength)
}
func (t *TLV) MarshalBinary() ([]byte, error) {
buf := make([]byte, 4+t.DataLength)
binary.BigEndian.PutUint16(buf[:2], t.Type)
binary.BigEndian.PutUint16(buf[2:4], t.DataLength)
copy(buf[4:], t.Data)
return buf, nil
}
func (t *TLV) UnmarshalBinary(data []byte) error {
if len(data) < 4 {
return io.ErrUnexpectedEOF
}
t.Type = Word(data[:2])
t.DataLength = Word(data[2:4])
if len(data) < 4+int(t.DataLength) {
return io.ErrUnexpectedEOF
}
t.Data = make([]byte, int(t.DataLength))
copy(t.Data, data[4:4+int(t.DataLength)])
return nil
}
func (t *TLV) String() string {
return fmt.Sprintf("TLV(%#x):\n%s", t.Type, prettyBytes(t.Data))
}
func UnmarshalTLVs(data []byte) ([]*TLV, error) {
tlvs := make([]*TLV, 0)
d := make([]byte, len(data))
copy(d, data)
for len(d) > 0 {
tlv := &TLV{}
if err := tlv.UnmarshalBinary(d); err != nil {
return nil, errors.Wrap(err, "enexpected end to unmarshalling TLVs")
}
tlvs = append(tlvs, tlv)
d = d[tlv.Len():]
}
return tlvs, nil
}
func FindTLV(tlvs []*TLV, tlvType uint16) *TLV {
for _, tlv := range tlvs {
if tlv.Type == tlvType {
return tlv
}
}
return nil
}
// type TLVReader struct {
// buf []byte
// pos int
// }
// func (r *TLVReader) ReadNextTLV() (*TLV, error) {
// if len(r.buf) < 4 {
// return nil, io.ErrUnexpectedEOF
// }
// t := &TLV{}
// t.Type = Word(r.buf[r.pos:r.pos+2])
// r.pos = r.pos + 2
// t.DataLength = Word(r.buf[r.pos : r.pos+2])
// r.pos = r.pos + 2
// copy(p[2:4], r.buf[r.pos:r.pos+2])
// r.pos = r.pos + 2
// // If there is not enough space to write the expected amount of data, error
// if dataLength > len(p)+4 {
// return 0, io.ErrUnexpectedEOF
// }
// n = n + copy(p[4:dataLength], r.buf[r.pos:r.pos+dataLength])
// r.pos = r.pos + dataLength
// return n, nil
// }
// func NewTLVReader(data []byte) *TLVReader {
// return &TLVReader{buf: data, pos: 0}
// }