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 }