package util import ( "encoding/binary" "errors" ) var ErrDecode = errors.New("decode") type Encoder struct { b []byte err error } func NewEncoder(dst []byte) *Encoder { return &Encoder{b: dst} } func (e *Encoder) Bytes() []byte { return e.b } func (e *Encoder) Err() error { return e.err } func (e *Encoder) U8(v uint8) { if e.err != nil { return } e.b = append(e.b, v) } func (e *Encoder) U32(v uint32) { if e.err != nil { return } var tmp [4]byte binary.LittleEndian.PutUint32(tmp[:], v) e.b = append(e.b, tmp[:]...) } func (e *Encoder) BytesFixed(p []byte) { if e.err != nil { return } e.b = append(e.b, p...) } func (e *Encoder) BytesLen(p []byte) { if e.err != nil { return } e.U32(uint32(len(p))) e.b = append(e.b, p...) } func (e *Encoder) String(s string) { e.BytesLen([]byte(s)) } func (e *Encoder) StringSlice(ss []string) { if e.err != nil { return } e.U32(uint32(len(ss))) for _, s := range ss { e.String(s) } } type Decoder struct { b []byte off int err error } func NewDecoder(src []byte) *Decoder { return &Decoder{b: src} } func (d *Decoder) Err() error { return d.err } func (d *Decoder) need(n int) bool { if d.err != nil { return false } if n < 0 || d.off+n > len(d.b) { d.err = ErrDecode return false } return true } func (d *Decoder) U8() uint8 { if !d.need(1) { return 0 } v := d.b[d.off] d.off++ return v } func (d *Decoder) U32() uint32 { if !d.need(4) { return 0 } v := binary.LittleEndian.Uint32(d.b[d.off : d.off+4]) d.off += 4 return v } func (d *Decoder) BytesFixed(n int) []byte { if !d.need(n) { return nil } out := d.b[d.off : d.off+n] d.off += n return out } func (d *Decoder) BytesLen() []byte { n := int(d.U32()) return d.BytesFixed(n) } func (d *Decoder) String() string { return string(d.BytesLen()) } func (d *Decoder) StringSlice() []string { n := int(d.U32()) if d.Err() != nil { return nil } out := make([]string, 0, n) for range n { out = append(out, d.String()) if d.Err() != nil { return nil } } return out }