// Copyright (c) quickfixengine.org All rights reserved. // // This file may be distributed under the terms of the quickfixengine.org // license as defined by quickfixengine.org and appearing in the file // LICENSE included in the packaging of this file. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING // THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A // PARTICULAR PURPOSE. // // See http://www.quickfixengine.org/LICENSE for licensing information. // // Contact ask@quickfixengine.org if any conditions of this licensing // are not clear to you. package quickfix import ( "bytes" "errors" "io" "time" ) const ( defaultBufSize = 4096 ) type parser struct { // Buffer is a slice of bigBuffer. bigBuffer, buffer []byte reader io.Reader lastRead time.Time } func newParser(reader io.Reader) *parser { return &parser{reader: reader} } func (p *parser) readMore() (int, error) { if len(p.buffer) == cap(p.buffer) { var newBuffer []byte switch { // Initialize the parser. case len(p.bigBuffer) == 0: p.bigBuffer = make([]byte, defaultBufSize) newBuffer = p.bigBuffer[0:0] // Shift buffer back to the start of bigBuffer. case 2*len(p.buffer) <= len(p.bigBuffer): newBuffer = p.bigBuffer[0:len(p.buffer)] // Reallocate big buffer with enough space to shift buffer. default: p.bigBuffer = make([]byte, 2*len(p.buffer)) newBuffer = p.bigBuffer[0:len(p.buffer)] } copy(newBuffer, p.buffer) p.buffer = newBuffer } n, e := p.reader.Read(p.buffer[len(p.buffer):cap(p.buffer)]) p.lastRead = time.Now() p.buffer = p.buffer[:len(p.buffer)+n] return n, e } func (p *parser) findIndex(delim []byte) (int, error) { return p.findIndexAfterOffset(0, delim) } func (p *parser) findIndexAfterOffset(offset int, delim []byte) (int, error) { for { if offset > len(p.buffer) { if n, err := p.readMore(); n == 0 && err != nil { return -1, err } continue } if index := bytes.Index(p.buffer[offset:], delim); index != -1 { return index + offset, nil } n, err := p.readMore() if n == 0 && err != nil { return -1, err } } } func (p *parser) findStart() (int, error) { return p.findIndex([]byte("8=")) } func (p *parser) findEndAfterOffset(offset int) (int, error) { index, err := p.findIndexAfterOffset(offset, []byte("\00110=")) if err != nil { return index, err } index, err = p.findIndexAfterOffset(index+1, []byte("\001")) if err != nil { return index, err } return index + 1, nil } func (p *parser) jumpLength() (int, error) { lengthIndex, err := p.findIndex([]byte("9=")) if err != nil { return 0, err } lengthIndex += 3 offset, err := p.findIndexAfterOffset(lengthIndex, []byte("\001")) if err != nil { return 0, err } if offset == lengthIndex { return 0, errors.New("No length given") } length, err := atoi(p.buffer[lengthIndex:offset]) if err != nil { return length, err } if length <= 0 { return length, errors.New("Invalid length") } return offset + length, nil } func (p *parser) ReadMessage() (msgBytes *bytes.Buffer, err error) { start, err := p.findStart() if err != nil { return } p.buffer = p.buffer[start:] index, err := p.jumpLength() if err != nil { return } index, err = p.findEndAfterOffset(index) if err != nil { return } msgBytes = new(bytes.Buffer) msgBytes.Reset() msgBytes.Write(p.buffer[:index]) p.buffer = p.buffer[index:] return }