youtubebeat/vendor/github.com/elastic/beats/libbeat/common/streambuf/ascii.go

251 lines
5.3 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package streambuf
// ASCII parsing support
import (
"bytes"
"errors"
)
var ErrExpectedDigit = errors.New("Expected digit")
// UntilCRLF collects all bytes until a CRLF ("\r\n") sequence is found. The
// returned byte slice will not contain the CRLF sequence.
// If CRLF was not found yet one of ErrNoMoreBytes or ErrUnexpectedEOB will be
// reported.
func (b *Buffer) UntilCRLF() ([]byte, error) {
if b.err != nil {
return nil, b.err
}
data := b.data[b.offset:]
for i, byte := range data {
if byte != '\r' {
continue
}
if len(data) < i+2 {
b.offset += i
return nil, b.bufferEndError()
}
if data[i+1] != '\n' {
// false alarm, continue
continue
}
// yay, found
end := i
data = b.data[b.mark : b.offset+end]
b.Advance(len(data) + 2)
return data, nil
}
b.offset += len(data)
return nil, b.bufferEndError()
}
// IgnoreSymbol will advance the read pointer until the first symbol not
// matching s is found.
func (b *Buffer) IgnoreSymbol(s uint8) error {
if b.err != nil {
return b.err
}
data := b.data[b.offset:]
for i, byte := range data {
if byte != s {
b.Advance(b.offset + i - b.mark)
return nil
}
}
b.offset += len(data)
return b.bufferEndError()
}
// IgnoreSymbols will advance the read pointer until the first symbol not matching
// set of symbols is found
func (b *Buffer) IgnoreSymbols(syms []byte) error {
if b.err != nil {
return b.err
}
data := b.data[b.offset:]
for i, byte := range data {
for _, other := range syms {
if byte == other {
goto next
}
}
// no match
b.Advance(b.offset + i - b.mark)
return nil
next:
}
b.offset += len(data)
return b.bufferEndError()
}
// UntilSymbol collects all bytes until symbol s is found. If errOnEnd is set to
// true, the collected byte slice will be returned if no more bytes are available
// for parsing, but s has not matched yet.
func (b *Buffer) UntilSymbol(s uint8, errOnEnd bool) ([]byte, error) {
if b.err != nil {
return nil, b.err
}
data := b.data[b.offset:]
for i, byte := range data {
if byte == s {
data := b.data[b.mark : b.offset+i]
b.Advance(len(data))
return data, nil
}
}
if errOnEnd {
b.offset += len(data)
return nil, b.bufferEndError()
}
data = b.data[b.mark:]
b.Advance(len(data))
return data, nil
}
// UintASCII will parse unsigned number from Buffer.
func (b *Buffer) UintASCII(errOnEnd bool) (uint64, error) {
if b.err != nil {
return 0, b.err
}
if len(b.data) <= b.mark { // end of buffer
return 0, b.bufferEndError()
}
end, err := b.asciiFindNumberEnd(b.offset, errOnEnd)
if err != nil {
return 0, err
}
// parse value
value, err := doParseNumber(b.data[b.mark:end])
if err != nil {
return 0, err
}
b.Advance(end - b.mark)
return value, nil
}
// IntASCII will parse (optionally) signed number from Buffer.
func (b *Buffer) IntASCII(errOnEnd bool) (int64, error) {
if b.err != nil {
return 0, b.err
}
if len(b.data) <= b.mark { // end of buffer
return 0, b.bufferEndError()
}
// check signedness of number
signed := b.data[b.mark] == '-'
start := b.mark
if signed {
start++
if len(b.data) <= start {
return 0, b.bufferEndError()
}
} else if b.data[b.mark] == '+' {
start++
if len(b.data) <= start {
return 0, b.bufferEndError()
}
}
// adapt offset to point to start of number
offset := b.offset
if b.offset == b.mark {
offset = start
}
end, err := b.asciiFindNumberEnd(offset, errOnEnd)
if err != nil {
return 0, err
}
value, err := doParseNumber(b.data[start:end])
if err != nil {
return 0, err
}
b.Advance(end - b.mark)
if signed {
return -int64(value), nil
}
return int64(value), nil
}
// MatchASCII checks the Buffer it's next byte sequence matched prefix. The
// read pointer is not advanced by AsciiPrefix.
func (b *Buffer) MatchASCII(prefix []byte) (bool, error) {
if b.err != nil {
return false, b.err
}
if !b.Avail(len(prefix)) {
return false, b.bufferEndError()
}
has := bytes.HasPrefix(b.data[b.mark:], prefix)
return has, nil
}
func (b *Buffer) asciiFindNumberEnd(start int, errOnEnd bool) (int, error) {
// find end of number
end := -1
for i, byte := range b.data[start:] {
if byte < '0' || '9' < byte {
end = i + start
break
}
}
// check end
if end < 0 {
if errOnEnd {
return -1, b.bufferEndError()
}
end = len(b.data)
}
return end, nil
}
func doParseNumber(buf []byte) (uint64, error) {
if len(buf) == 0 {
return 0, ErrExpectedDigit
}
var value uint64
for _, byte := range buf {
value = uint64(byte-'0') + 10*value
}
return value, nil
}
// binary parsing support