| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- package framestream
- import (
- "bufio"
- "bytes"
- "encoding/binary"
- "io"
- )
- const CONTROL_ACCEPT = 0x01
- const CONTROL_START = 0x02
- const CONTROL_STOP = 0x03
- const CONTROL_READY = 0x04
- const CONTROL_FINISH = 0x05
- const CONTROL_FIELD_CONTENT_TYPE = 0x01
- const CONTROL_FRAME_LENGTH_MAX = 512
- type ControlFrame struct {
- ControlType uint32
- ContentTypes [][]byte
- }
- var ControlStart = ControlFrame{ControlType: CONTROL_START}
- var ControlStop = ControlFrame{ControlType: CONTROL_STOP}
- var ControlReady = ControlFrame{ControlType: CONTROL_READY}
- var ControlAccept = ControlFrame{ControlType: CONTROL_ACCEPT}
- var ControlFinish = ControlFrame{ControlType: CONTROL_FINISH}
- func (c *ControlFrame) Encode(w io.Writer) (err error) {
- var buf bytes.Buffer
- err = binary.Write(&buf, binary.BigEndian, c.ControlType)
- if err != nil {
- return
- }
- for _, ctype := range c.ContentTypes {
- err = binary.Write(&buf, binary.BigEndian, uint32(CONTROL_FIELD_CONTENT_TYPE))
- if err != nil {
- return
- }
- err = binary.Write(&buf, binary.BigEndian, uint32(len(ctype)))
- if err != nil {
- return
- }
- _, err = buf.Write(ctype)
- if err != nil {
- return
- }
- }
- err = binary.Write(w, binary.BigEndian, uint32(0))
- if err != nil {
- return
- }
- err = binary.Write(w, binary.BigEndian, uint32(buf.Len()))
- if err != nil {
- return
- }
- _, err = buf.WriteTo(w)
- return
- }
- func (c *ControlFrame) EncodeFlush(w *bufio.Writer) error {
- if err := c.Encode(w); err != nil {
- return err
- }
- return w.Flush()
- }
- func (c *ControlFrame) Decode(r io.Reader) (err error) {
- var cflen uint32
- err = binary.Read(r, binary.BigEndian, &cflen)
- if err != nil {
- return
- }
- if cflen > CONTROL_FRAME_LENGTH_MAX {
- return ErrDecode
- }
- if cflen < 4 {
- return ErrDecode
- }
- err = binary.Read(r, binary.BigEndian, &c.ControlType)
- if err != nil {
- return
- }
- cflen -= 4
- if cflen > 0 {
- cfields := make([]byte, int(cflen))
- _, err = io.ReadFull(r, cfields)
- if err != nil {
- return
- }
- for len(cfields) > 8 {
- cftype := binary.BigEndian.Uint32(cfields[:4])
- cfields = cfields[4:]
- if cftype != CONTROL_FIELD_CONTENT_TYPE {
- return ErrDecode
- }
- cflen := int(binary.BigEndian.Uint32(cfields[:4]))
- cfields = cfields[4:]
- if cflen > len(cfields) {
- return ErrDecode
- }
- c.ContentTypes = append(c.ContentTypes, cfields[:cflen])
- cfields = cfields[cflen:]
- }
- if len(cfields) > 0 {
- return ErrDecode
- }
- }
- return
- }
- func (c *ControlFrame) DecodeEscape(r io.Reader) error {
- var zero uint32
- err := binary.Read(r, binary.BigEndian, &zero)
- if err != nil {
- return err
- }
- if zero != 0 {
- return ErrDecode
- }
- return c.Decode(r)
- }
- func (c *ControlFrame) DecodeTypeEscape(r io.Reader, ctype uint32) error {
- err := c.DecodeEscape(r)
- if err != nil {
- return err
- }
- if ctype != c.ControlType {
- return ErrDecode
- }
- return nil
- }
- // ChooseContentType selects a content type from the ControlFrame which
- // also exists in the supplied ctypes. Preference is given to values occurring
- // earliest in ctypes.
- //
- // ChooseContentType returns the chosen content type, which may be nil, and
- // a bool value indicating whether a matching type was found.
- //
- // If either the ControlFrame types or ctypes is empty, ChooseContentType
- // returns nil as a matching content type.
- func (c *ControlFrame) ChooseContentType(ctypes [][]byte) (typ []byte, found bool) {
- if c.ContentTypes == nil || ctypes == nil {
- return nil, true
- }
- tm := make(map[string]bool)
- for _, cfctype := range c.ContentTypes {
- tm[string(cfctype)] = true
- }
- for _, ctype := range ctypes {
- if tm[string(ctype)] {
- return ctype, true
- }
- }
- return nil, false
- }
- func (c *ControlFrame) MatchContentType(ctype []byte) bool {
- for _, cfctype := range c.ContentTypes {
- if bytes.Compare(ctype, cfctype) == 0 {
- return true
- }
- }
- return len(c.ContentTypes) == 0
- }
- func (c *ControlFrame) SetContentTypes(ctypes [][]byte) {
- c.ContentTypes = ctypes
- }
- func (c *ControlFrame) SetContentType(ctype []byte) {
- if ctype != nil {
- c.SetContentTypes([][]byte{ctype})
- } else {
- c.ContentTypes = nil
- }
- }
|