/* netstring -- netstring format serialization library Copyright (C) 2015 Sergey Matveev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package netstring import ( "bufio" "io" "strconv" ) type Reader struct { reader *bufio.Reader prefix []byte err error size uint64 n int } func NewReader(r io.Reader) *Reader { return &Reader{ reader: bufio.NewReader(r), prefix: make([]byte, MaxPrefixSize), } } // Parse incoming netstring prefix. It returns netstring's incoming // data length. After using this method you can call either Read() // or Discard() methods. User can check if incoming data length is // too big. func (self *Reader) Iter() (size uint64, err error) { self.n = 0 for self.n < MaxPrefixSize { self.prefix[self.n], self.err = self.reader.ReadByte() if self.err != nil { return 0, self.err } if self.prefix[self.n] == ':' { break } self.n++ } self.size, self.err = strconv.ParseUint( string(self.prefix[:self.n]), 10, 64, ) if self.err != nil { return 0, self.err } return self.size, nil } func (self *Reader) terminator() bool { self.prefix[0], self.err = self.reader.ReadByte() if self.err != nil { return false } if self.prefix[0] != ',' { self.err = ErrTerminator return false } return true } // Receive the full netstring message. This method is called after // Iter() and user must preallocate buf. If buf size is smaller than // incoming data size, then function will return an error. Also it // checks the final terminator character and will return an error if // it won't find it. func (self *Reader) Read(buf []byte) error { if self.err != nil { return ErrState } if uint64(cap(buf)) < self.size { return ErrBufSize } _, self.err = io.ReadAtLeast(self.reader, buf, int(self.size)) if self.err != nil { return self.err } if !self.terminator() { return self.err } return nil } // Discard (skip) netstring message. This method is called after Iter(). // It reads and ignores data from the reader and checks that terminator // character is valid. func (self *Reader) Discard() error { if self.err != nil { return ErrState } if _, self.err = self.reader.Discard(int(self.size)); self.err != nil { return self.err } if !self.terminator() { return self.err } return nil }