github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/internal/restic/rand_reader.go (about) 1 package restic 2 3 import ( 4 "io" 5 "math/rand" 6 7 "github.com/restic/restic/internal/errors" 8 ) 9 10 // RandReader allows reading from a rand.Rand. 11 type RandReader struct { 12 rnd *rand.Rand 13 buf []byte 14 } 15 16 // NewRandReader creates a new Reader from a random source. 17 func NewRandReader(rnd *rand.Rand) io.Reader { 18 return &RandReader{rnd: rnd, buf: make([]byte, 0, 7)} 19 } 20 21 func (rd *RandReader) read(p []byte) (n int, err error) { 22 if len(p)%7 != 0 { 23 panic("invalid buffer length, not multiple of 7") 24 } 25 26 rnd := rd.rnd 27 for i := 0; i < len(p); i += 7 { 28 val := rnd.Int63() 29 30 p[i+0] = byte(val >> 0) 31 p[i+1] = byte(val >> 8) 32 p[i+2] = byte(val >> 16) 33 p[i+3] = byte(val >> 24) 34 p[i+4] = byte(val >> 32) 35 p[i+5] = byte(val >> 40) 36 p[i+6] = byte(val >> 48) 37 } 38 39 return len(p), nil 40 } 41 42 func (rd *RandReader) Read(p []byte) (int, error) { 43 // first, copy buffer to p 44 pos := copy(p, rd.buf) 45 copy(rd.buf, rd.buf[pos:]) 46 47 // shorten buf and p accordingly 48 rd.buf = rd.buf[:len(rd.buf)-pos] 49 p = p[pos:] 50 51 // if this is enough to fill p, return 52 if len(p) == 0 { 53 return pos, nil 54 } 55 56 // load multiple of 7 byte 57 l := (len(p) / 7) * 7 58 n, err := rd.read(p[:l]) 59 pos += n 60 if err != nil { 61 return pos, errors.Wrap(err, "Read") 62 } 63 p = p[n:] 64 65 // load 7 byte to temp buffer 66 rd.buf = rd.buf[:7] 67 n, err = rd.read(rd.buf) 68 if err != nil { 69 return pos, errors.Wrap(err, "Read") 70 } 71 72 // copy the remaining bytes from the buffer to p 73 n = copy(p, rd.buf) 74 pos += n 75 76 // save the remaining bytes in rd.buf 77 n = copy(rd.buf, rd.buf[n:]) 78 rd.buf = rd.buf[:n] 79 80 return pos, nil 81 }