github.com/streamdal/segmentio-kafka-go@v0.4.47-streamdal/compress/snappy/xerial.go (about) 1 package snappy 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "io" 8 9 "github.com/klauspost/compress/snappy" 10 ) 11 12 const defaultBufferSize = 32 * 1024 13 14 // An implementation of io.Reader which consumes a stream of xerial-framed 15 // snappy-encoeded data. The framing is optional, if no framing is detected 16 // the reader will simply forward the bytes from its underlying stream. 17 type xerialReader struct { 18 reader io.Reader 19 header [16]byte 20 input []byte 21 output []byte 22 offset int64 23 nbytes int64 24 decode func([]byte, []byte) ([]byte, error) 25 } 26 27 func (x *xerialReader) Reset(r io.Reader) { 28 x.reader = r 29 x.input = x.input[:0] 30 x.output = x.output[:0] 31 x.header = [16]byte{} 32 x.offset = 0 33 x.nbytes = 0 34 } 35 36 func (x *xerialReader) Read(b []byte) (int, error) { 37 for { 38 if x.offset < int64(len(x.output)) { 39 n := copy(b, x.output[x.offset:]) 40 x.offset += int64(n) 41 return n, nil 42 } 43 44 n, err := x.readChunk(b) 45 if err != nil { 46 return 0, err 47 } 48 if n > 0 { 49 return n, nil 50 } 51 } 52 } 53 54 func (x *xerialReader) WriteTo(w io.Writer) (int64, error) { 55 wn := int64(0) 56 57 for { 58 for x.offset < int64(len(x.output)) { 59 n, err := w.Write(x.output[x.offset:]) 60 wn += int64(n) 61 x.offset += int64(n) 62 if err != nil { 63 return wn, err 64 } 65 } 66 67 if _, err := x.readChunk(nil); err != nil { 68 if errors.Is(err, io.EOF) { 69 err = nil 70 } 71 return wn, err 72 } 73 } 74 } 75 76 func (x *xerialReader) readChunk(dst []byte) (int, error) { 77 x.output = x.output[:0] 78 x.offset = 0 79 prefix := 0 80 81 if x.nbytes == 0 { 82 n, err := x.readFull(x.header[:]) 83 if err != nil && n == 0 { 84 return 0, err 85 } 86 prefix = n 87 } 88 89 if isXerialHeader(x.header[:]) { 90 if cap(x.input) < 4 { 91 x.input = make([]byte, 4, defaultBufferSize) 92 } else { 93 x.input = x.input[:4] 94 } 95 96 _, err := x.readFull(x.input) 97 if err != nil { 98 return 0, err 99 } 100 101 frame := int(binary.BigEndian.Uint32(x.input)) 102 if cap(x.input) < frame { 103 x.input = make([]byte, frame, align(frame, defaultBufferSize)) 104 } else { 105 x.input = x.input[:frame] 106 } 107 108 if _, err := x.readFull(x.input); err != nil { 109 return 0, err 110 } 111 } else { 112 if cap(x.input) == 0 { 113 x.input = make([]byte, 0, defaultBufferSize) 114 } else { 115 x.input = x.input[:0] 116 } 117 118 if prefix > 0 { 119 x.input = append(x.input, x.header[:prefix]...) 120 } 121 122 for { 123 if len(x.input) == cap(x.input) { 124 b := make([]byte, len(x.input), 2*cap(x.input)) 125 copy(b, x.input) 126 x.input = b 127 } 128 129 n, err := x.read(x.input[len(x.input):cap(x.input)]) 130 x.input = x.input[:len(x.input)+n] 131 if err != nil { 132 if errors.Is(err, io.EOF) && len(x.input) > 0 { 133 break 134 } 135 return 0, err 136 } 137 } 138 } 139 140 var n int 141 var err error 142 143 if x.decode == nil { 144 x.output, x.input, err = x.input, x.output, nil 145 } else if n, err = snappy.DecodedLen(x.input); n <= len(dst) && err == nil { 146 // If the output buffer is large enough to hold the decode value, 147 // write it there directly instead of using the intermediary output 148 // buffer. 149 _, err = x.decode(dst, x.input) 150 } else { 151 var b []byte 152 n = 0 153 b, err = x.decode(x.output[:cap(x.output)], x.input) 154 if err == nil { 155 x.output = b 156 } 157 } 158 159 return n, err 160 } 161 162 func (x *xerialReader) read(b []byte) (int, error) { 163 n, err := x.reader.Read(b) 164 x.nbytes += int64(n) 165 return n, err 166 } 167 168 func (x *xerialReader) readFull(b []byte) (int, error) { 169 n, err := io.ReadFull(x.reader, b) 170 x.nbytes += int64(n) 171 return n, err 172 } 173 174 // An implementation of a xerial-framed snappy-encoded output stream. 175 // Each Write made to the writer is framed with a xerial header. 176 type xerialWriter struct { 177 writer io.Writer 178 header [16]byte 179 input []byte 180 output []byte 181 nbytes int64 182 framed bool 183 encode func([]byte, []byte) []byte 184 } 185 186 func (x *xerialWriter) Reset(w io.Writer) { 187 x.writer = w 188 x.input = x.input[:0] 189 x.output = x.output[:0] 190 x.nbytes = 0 191 } 192 193 func (x *xerialWriter) ReadFrom(r io.Reader) (int64, error) { 194 wn := int64(0) 195 196 if cap(x.input) == 0 { 197 x.input = make([]byte, 0, defaultBufferSize) 198 } 199 200 for { 201 if x.full() { 202 x.grow() 203 } 204 205 n, err := r.Read(x.input[len(x.input):cap(x.input)]) 206 wn += int64(n) 207 x.input = x.input[:len(x.input)+n] 208 209 if x.fullEnough() { 210 if err := x.Flush(); err != nil { 211 return wn, err 212 } 213 } 214 215 if err != nil { 216 if errors.Is(err, io.EOF) { 217 err = nil 218 } 219 return wn, err 220 } 221 } 222 } 223 224 func (x *xerialWriter) Write(b []byte) (int, error) { 225 wn := 0 226 227 if cap(x.input) == 0 { 228 x.input = make([]byte, 0, defaultBufferSize) 229 } 230 231 for len(b) > 0 { 232 if x.full() { 233 x.grow() 234 } 235 236 n := copy(x.input[len(x.input):cap(x.input)], b) 237 b = b[n:] 238 wn += n 239 x.input = x.input[:len(x.input)+n] 240 241 if x.fullEnough() { 242 if err := x.Flush(); err != nil { 243 return wn, err 244 } 245 } 246 } 247 248 return wn, nil 249 } 250 251 func (x *xerialWriter) Flush() error { 252 if len(x.input) == 0 { 253 return nil 254 } 255 256 var b []byte 257 if x.encode == nil { 258 b = x.input 259 } else { 260 x.output = x.encode(x.output[:cap(x.output)], x.input) 261 b = x.output 262 } 263 264 x.input = x.input[:0] 265 x.output = x.output[:0] 266 267 if x.framed && x.nbytes == 0 { 268 writeXerialHeader(x.header[:]) 269 _, err := x.write(x.header[:]) 270 if err != nil { 271 return err 272 } 273 } 274 275 if x.framed { 276 writeXerialFrame(x.header[:4], len(b)) 277 _, err := x.write(x.header[:4]) 278 if err != nil { 279 return err 280 } 281 } 282 283 _, err := x.write(b) 284 return err 285 } 286 287 func (x *xerialWriter) write(b []byte) (int, error) { 288 n, err := x.writer.Write(b) 289 x.nbytes += int64(n) 290 return n, err 291 } 292 293 func (x *xerialWriter) full() bool { 294 return len(x.input) == cap(x.input) 295 } 296 297 func (x *xerialWriter) fullEnough() bool { 298 return x.framed && (cap(x.input)-len(x.input)) < 1024 299 } 300 301 func (x *xerialWriter) grow() { 302 tmp := make([]byte, len(x.input), 2*cap(x.input)) 303 copy(tmp, x.input) 304 x.input = tmp 305 } 306 307 func align(n, a int) int { 308 if (n % a) == 0 { 309 return n 310 } 311 return ((n / a) + 1) * a 312 } 313 314 var ( 315 xerialHeader = [...]byte{130, 83, 78, 65, 80, 80, 89, 0} 316 xerialVersionInfo = [...]byte{0, 0, 0, 1, 0, 0, 0, 1} 317 ) 318 319 func isXerialHeader(src []byte) bool { 320 return len(src) >= 16 && bytes.Equal(src[:8], xerialHeader[:]) 321 } 322 323 func writeXerialHeader(b []byte) { 324 copy(b[:8], xerialHeader[:]) 325 copy(b[8:], xerialVersionInfo[:]) 326 } 327 328 func writeXerialFrame(b []byte, n int) { 329 binary.BigEndian.PutUint32(b, uint32(n)) 330 }