Files
mikrotik-exporter/vendor/gopkg.in/routeros.v2/proto/reader.go
2017-08-27 23:27:11 -04:00

111 lines
2.0 KiB
Go

package proto
import (
"bufio"
"bytes"
"fmt"
"io"
)
// Reader reads sentences from a RouterOS device.
type Reader interface {
ReadSentence() (*Sentence, error)
}
type reader struct {
*bufio.Reader
}
// NewReader returns a new Reader to read from r.
func NewReader(r io.Reader) Reader {
return &reader{bufio.NewReader(r)}
}
// ReadSentence reads a sentence.
func (r *reader) ReadSentence() (*Sentence, error) {
sen := NewSentence()
for {
b, err := r.readWord()
if err != nil {
return nil, err
}
if len(b) == 0 {
return sen, nil
}
// Ex.: !re, !done
if sen.Word == "" {
sen.Word = string(b)
continue
}
// Command tag.
if bytes.HasPrefix(b, []byte(".tag=")) {
sen.Tag = string(b[5:])
continue
}
// Ex.: =key=value, =key
if bytes.HasPrefix(b, []byte("=")) {
t := bytes.SplitN(b[1:], []byte("="), 2)
if len(t) == 1 {
t = append(t, []byte{})
}
p := Pair{string(t[0]), string(t[1])}
sen.List = append(sen.List, p)
sen.Map[p.Key] = p.Value
continue
}
return nil, fmt.Errorf("invalid RouterOS sentence word: %#q", b)
}
}
func (r *reader) readNumber(size int) (int64, error) {
b := make([]byte, size)
_, err := io.ReadFull(r, b)
if err != nil {
return -1, err
}
var num int64
for _, ch := range b {
num = num<<8 | int64(ch)
}
return num, nil
}
func (r *reader) readLength() (int64, error) {
l, err := r.readNumber(1)
if err != nil {
return -1, err
}
var n int64
switch {
case l&0x80 == 0x00:
case (l & 0xC0) == 0x80:
n, err = r.readNumber(1)
l = l & ^0xC0 << 8 | n
case l&0xE0 == 0xC0:
n, err = r.readNumber(2)
l = l & ^0xE0 << 16 | n
case l&0xF0 == 0xE0:
n, err = r.readNumber(3)
l = l & ^0xF0 << 24 | n
case l&0xF8 == 0xF0:
l, err = r.readNumber(4)
}
if err != nil {
return -1, err
}
return l, nil
}
func (r *reader) readWord() ([]byte, error) {
l, err := r.readLength()
if err != nil {
return nil, err
}
b := make([]byte, l)
_, err = io.ReadFull(r, b)
if err != nil {
return nil, err
}
return b, nil
}