github.com/artpar/rclone@v1.67.3/backend/mailru/api/helpers.go (about)

     1  package api
     2  
     3  // BIN protocol helpers
     4  
     5  import (
     6  	"bufio"
     7  	"bytes"
     8  	"encoding/binary"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"time"
    13  
    14  	"github.com/artpar/rclone/lib/readers"
    15  )
    16  
    17  // protocol errors
    18  var (
    19  	ErrorPrematureEOF  = errors.New("premature EOF")
    20  	ErrorInvalidLength = errors.New("invalid length")
    21  	ErrorZeroTerminate = errors.New("string must end with zero")
    22  )
    23  
    24  // BinWriter is a binary protocol writer
    25  type BinWriter struct {
    26  	b *bytes.Buffer // growing byte buffer
    27  	a []byte        // temporary buffer for next varint
    28  }
    29  
    30  // NewBinWriter creates a binary protocol helper
    31  func NewBinWriter() *BinWriter {
    32  	return &BinWriter{
    33  		b: new(bytes.Buffer),
    34  		a: make([]byte, binary.MaxVarintLen64),
    35  	}
    36  }
    37  
    38  // Bytes returns binary data
    39  func (w *BinWriter) Bytes() []byte {
    40  	return w.b.Bytes()
    41  }
    42  
    43  // Reader returns io.Reader with binary data
    44  func (w *BinWriter) Reader() io.Reader {
    45  	return bytes.NewReader(w.b.Bytes())
    46  }
    47  
    48  // WritePu16 writes a short as unsigned varint
    49  func (w *BinWriter) WritePu16(val int) {
    50  	if val < 0 || val > 65535 {
    51  		panic(fmt.Sprintf("Invalid UInt16 %v", val))
    52  	}
    53  	w.WritePu64(int64(val))
    54  }
    55  
    56  // WritePu32 writes a signed long as unsigned varint
    57  func (w *BinWriter) WritePu32(val int64) {
    58  	if val < 0 || val > 4294967295 {
    59  		panic(fmt.Sprintf("Invalid UInt32 %v", val))
    60  	}
    61  	w.WritePu64(val)
    62  }
    63  
    64  // WritePu64 writes an unsigned (actually, signed) long as unsigned varint
    65  func (w *BinWriter) WritePu64(val int64) {
    66  	if val < 0 {
    67  		panic(fmt.Sprintf("Invalid UInt64 %v", val))
    68  	}
    69  	w.b.Write(w.a[:binary.PutUvarint(w.a, uint64(val))])
    70  }
    71  
    72  // WriteP64 writes an signed long as unsigned varint
    73  func (w *BinWriter) WriteP64(val int64) {
    74  	w.b.Write(w.a[:binary.PutUvarint(w.a, uint64(val))])
    75  }
    76  
    77  // WriteString writes a zero-terminated string
    78  func (w *BinWriter) WriteString(str string) {
    79  	buf := []byte(str)
    80  	w.WritePu64(int64(len(buf) + 1))
    81  	w.b.Write(buf)
    82  	w.b.WriteByte(0)
    83  }
    84  
    85  // Write writes a byte buffer
    86  func (w *BinWriter) Write(buf []byte) {
    87  	w.b.Write(buf)
    88  }
    89  
    90  // WriteWithLength writes a byte buffer prepended with its length as varint
    91  func (w *BinWriter) WriteWithLength(buf []byte) {
    92  	w.WritePu64(int64(len(buf)))
    93  	w.b.Write(buf)
    94  }
    95  
    96  // BinReader is a binary protocol reader helper
    97  type BinReader struct {
    98  	b     *bufio.Reader
    99  	count *readers.CountingReader
   100  	err   error // keeps the first error encountered
   101  }
   102  
   103  // NewBinReader creates a binary protocol reader helper
   104  func NewBinReader(reader io.Reader) *BinReader {
   105  	r := &BinReader{}
   106  	r.count = readers.NewCountingReader(reader)
   107  	r.b = bufio.NewReader(r.count)
   108  	return r
   109  }
   110  
   111  // Count returns number of bytes read
   112  func (r *BinReader) Count() uint64 {
   113  	return r.count.BytesRead()
   114  }
   115  
   116  // Error returns first encountered error or nil
   117  func (r *BinReader) Error() error {
   118  	return r.err
   119  }
   120  
   121  // check() keeps the first error encountered in a stream
   122  func (r *BinReader) check(err error) bool {
   123  	if err == nil {
   124  		return true
   125  	}
   126  	if r.err == nil {
   127  		// keep the first error
   128  		r.err = err
   129  	}
   130  	if err != io.EOF {
   131  		panic(fmt.Sprintf("Error parsing response: %v", err))
   132  	}
   133  	return false
   134  }
   135  
   136  // ReadByteAsInt reads a single byte as uint32, returns -1 for EOF or errors
   137  func (r *BinReader) ReadByteAsInt() int {
   138  	if octet, err := r.b.ReadByte(); r.check(err) {
   139  		return int(octet)
   140  	}
   141  	return -1
   142  }
   143  
   144  // ReadByteAsShort reads a single byte as uint16, returns -1 for EOF or errors
   145  func (r *BinReader) ReadByteAsShort() int16 {
   146  	if octet, err := r.b.ReadByte(); r.check(err) {
   147  		return int16(octet)
   148  	}
   149  	return -1
   150  }
   151  
   152  // ReadIntSpl reads two bytes as little-endian uint16, returns -1 for EOF or errors
   153  func (r *BinReader) ReadIntSpl() int {
   154  	var val uint16
   155  	if r.check(binary.Read(r.b, binary.LittleEndian, &val)) {
   156  		return int(val)
   157  	}
   158  	return -1
   159  }
   160  
   161  // ReadULong returns uint64 equivalent of -1 for EOF or errors
   162  func (r *BinReader) ReadULong() uint64 {
   163  	if val, err := binary.ReadUvarint(r.b); r.check(err) {
   164  		return val
   165  	}
   166  	return 0xffffffffffffffff
   167  }
   168  
   169  // ReadPu32 returns -1 for EOF or errors
   170  func (r *BinReader) ReadPu32() int64 {
   171  	if val, err := binary.ReadUvarint(r.b); r.check(err) {
   172  		return int64(val)
   173  	}
   174  	return -1
   175  }
   176  
   177  // ReadNBytes reads given number of bytes, returns invalid data for EOF or errors
   178  func (r *BinReader) ReadNBytes(len int) []byte {
   179  	buf := make([]byte, len)
   180  	n, err := r.b.Read(buf)
   181  	if r.check(err) {
   182  		return buf
   183  	}
   184  	if n != len {
   185  		r.check(ErrorPrematureEOF)
   186  	}
   187  	return buf
   188  }
   189  
   190  // ReadBytesByLength reads buffer length and its bytes
   191  func (r *BinReader) ReadBytesByLength() []byte {
   192  	len := r.ReadPu32()
   193  	if len < 0 {
   194  		r.check(ErrorInvalidLength)
   195  		return []byte{}
   196  	}
   197  	return r.ReadNBytes(int(len))
   198  }
   199  
   200  // ReadString reads a zero-terminated string with length
   201  func (r *BinReader) ReadString() string {
   202  	len := int(r.ReadPu32())
   203  	if len < 1 {
   204  		r.check(ErrorInvalidLength)
   205  		return ""
   206  	}
   207  	buf := make([]byte, len-1)
   208  	n, err := r.b.Read(buf)
   209  	if !r.check(err) {
   210  		return ""
   211  	}
   212  	if n != len-1 {
   213  		r.check(ErrorPrematureEOF)
   214  		return ""
   215  	}
   216  	zeroByte, err := r.b.ReadByte()
   217  	if !r.check(err) {
   218  		return ""
   219  	}
   220  	if zeroByte != 0 {
   221  		r.check(ErrorZeroTerminate)
   222  		return ""
   223  	}
   224  	return string(buf)
   225  }
   226  
   227  // ReadDate reads a Unix encoded time
   228  func (r *BinReader) ReadDate() time.Time {
   229  	return time.Unix(r.ReadPu32(), 0)
   230  }