59 lines
1.2 KiB
Go
59 lines
1.2 KiB
Go
package readers
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// This is the smallest prime less than 256
|
|
//
|
|
// Using a prime here means we are less likely to hit repeating patterns
|
|
const patternReaderModulo = 251
|
|
|
|
// NewPatternReader creates a reader, that returns a deterministic byte pattern.
|
|
// After length bytes are read
|
|
func NewPatternReader(length int64) io.ReadSeeker {
|
|
return &patternReader{
|
|
length: length,
|
|
}
|
|
}
|
|
|
|
type patternReader struct {
|
|
offset int64
|
|
length int64
|
|
c byte
|
|
}
|
|
|
|
func (r *patternReader) Read(p []byte) (n int, err error) {
|
|
for i := range p {
|
|
if r.offset >= r.length {
|
|
return n, io.EOF
|
|
}
|
|
p[i] = r.c
|
|
r.c = (r.c + 1) % patternReaderModulo
|
|
r.offset++
|
|
n++
|
|
}
|
|
return
|
|
}
|
|
|
|
// Seek implements the io.Seeker interface.
|
|
func (r *patternReader) Seek(offset int64, whence int) (abs int64, err error) {
|
|
switch whence {
|
|
case io.SeekStart:
|
|
abs = offset
|
|
case io.SeekCurrent:
|
|
abs = r.offset + offset
|
|
case io.SeekEnd:
|
|
abs = r.length + offset
|
|
default:
|
|
return 0, errors.New("patternReader: invalid whence")
|
|
}
|
|
if abs < 0 {
|
|
return 0, errors.New("patternReader: negative position")
|
|
}
|
|
r.offset = abs
|
|
r.c = byte(abs % patternReaderModulo)
|
|
return abs, nil
|
|
}
|