| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- package sdp
- import (
- "errors"
- "fmt"
- "io"
- )
- var errDocumentStart = errors.New("already on document start")
- type syntaxError struct {
- s string
- i int
- }
- func (e syntaxError) Error() string {
- if e.i < 0 {
- e.i = 0
- }
- head, middle, tail := e.s[:e.i], e.s[e.i:e.i+1], e.s[e.i+1:]
- return fmt.Sprintf("%s --> %s <-- %s", head, middle, tail)
- }
- type baseLexer struct {
- value []byte
- pos int
- }
- func (l baseLexer) syntaxError() error {
- return syntaxError{s: string(l.value), i: l.pos - 1}
- }
- func (l *baseLexer) unreadByte() error {
- if l.pos <= 0 {
- return errDocumentStart
- }
- l.pos--
- return nil
- }
- func (l *baseLexer) readByte() (byte, error) {
- if l.pos >= len(l.value) {
- return byte(0), io.EOF
- }
- ch := l.value[l.pos]
- l.pos++
- return ch, nil
- }
- func (l *baseLexer) nextLine() error {
- for {
- ch, err := l.readByte()
- if errors.Is(err, io.EOF) {
- return nil
- } else if err != nil {
- return err
- }
- if !isNewline(ch) {
- return l.unreadByte()
- }
- }
- }
- func (l *baseLexer) readWhitespace() error {
- for {
- ch, err := l.readByte()
- if errors.Is(err, io.EOF) {
- return nil
- } else if err != nil {
- return err
- }
- if !isWhitespace(ch) {
- return l.unreadByte()
- }
- }
- }
- func (l *baseLexer) readUint64Field() (i uint64, err error) {
- for {
- ch, err := l.readByte()
- if errors.Is(err, io.EOF) && i > 0 {
- break
- } else if err != nil {
- return i, err
- }
- if isNewline(ch) {
- if err := l.unreadByte(); err != nil {
- return i, err
- }
- break
- }
- if isWhitespace(ch) {
- if err := l.readWhitespace(); err != nil {
- return i, err
- }
- break
- }
- switch ch {
- case '0':
- i *= 10
- case '1':
- i = i*10 + 1
- case '2':
- i = i*10 + 2
- case '3':
- i = i*10 + 3
- case '4':
- i = i*10 + 4
- case '5':
- i = i*10 + 5
- case '6':
- i = i*10 + 6
- case '7':
- i = i*10 + 7
- case '8':
- i = i*10 + 8
- case '9':
- i = i*10 + 9
- default:
- return i, l.syntaxError()
- }
- }
- return i, nil
- }
- // Returns next field on this line or empty string if no more fields on line
- func (l *baseLexer) readField() (string, error) {
- start := l.pos
- var stop int
- for {
- stop = l.pos
- ch, err := l.readByte()
- if errors.Is(err, io.EOF) && stop > start {
- break
- } else if err != nil {
- return "", err
- }
- if isNewline(ch) {
- if err := l.unreadByte(); err != nil {
- return "", err
- }
- break
- }
- if isWhitespace(ch) {
- if err := l.readWhitespace(); err != nil {
- return "", err
- }
- break
- }
- }
- return string(l.value[start:stop]), nil
- }
- // Returns symbols until line end
- func (l *baseLexer) readLine() (string, error) {
- start := l.pos
- trim := 1
- for {
- ch, err := l.readByte()
- if err != nil {
- return "", err
- }
- if ch == '\r' {
- trim++
- }
- if ch == '\n' {
- return string(l.value[start : l.pos-trim]), nil
- }
- }
- }
- func (l *baseLexer) readString(until byte) (string, error) {
- start := l.pos
- for {
- ch, err := l.readByte()
- if err != nil {
- return "", err
- }
- if ch == until {
- return string(l.value[start:l.pos]), nil
- }
- }
- }
- func (l *baseLexer) readType() (string, error) {
- for {
- b, err := l.readByte()
- if err != nil {
- return "", err
- }
- if isNewline(b) {
- continue
- }
- err = l.unreadByte()
- if err != nil {
- return "", err
- }
- key, err := l.readString('=')
- if err != nil {
- return key, err
- }
- if len(key) == 2 {
- return key, nil
- }
- return key, l.syntaxError()
- }
- }
- func isNewline(ch byte) bool { return ch == '\n' || ch == '\r' }
- func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' }
- func anyOf(element string, data ...string) bool {
- for _, v := range data {
- if element == v {
- return true
- }
- }
- return false
- }
|