github.com/sashka/siva@v1.6.0/reader.go (about) 1 package siva 2 3 import ( 4 "errors" 5 "io" 6 ) 7 8 var ( 9 ErrPendingContent = errors.New("entry wasn't fully read") 10 ErrInvalidCheckshum = errors.New("invalid checksum") 11 ErrInvalidReaderAt = errors.New("reader provided dosen't implement ReaderAt interface") 12 ) 13 14 // A Reader provides random access to the contents of a siva archive. 15 type Reader interface { 16 io.Reader 17 Seek(e *IndexEntry) (int64, error) 18 Index() (Index, error) 19 Get(e *IndexEntry) (*io.SectionReader, error) 20 } 21 22 type reader struct { 23 r io.ReadSeeker 24 25 getIndexFunc func() (Index, error) 26 index Index 27 current *IndexEntry 28 pending uint64 29 offset uint64 30 } 31 32 // NewReader creates a new Reader reading from r, reader requires be seekable 33 // and optionally should implement io.ReaderAt to make usage of the Get method 34 func NewReader(r io.ReadSeeker) Reader { 35 return &reader{r: r} 36 } 37 38 // NewReaderWithOffset creates a new Reader giving the position of the index. 39 // This is useful to open siva files that are being written or reading an 40 // old index. 41 func NewReaderWithOffset(r io.ReadSeeker, o uint64) Reader { 42 return &reader{ 43 r: r, 44 offset: o, 45 } 46 } 47 48 func newReaderWithIndex(r io.ReadSeeker, getIndexFunc func() (Index, error)) *reader { 49 return &reader{ 50 r: r, 51 getIndexFunc: getIndexFunc, 52 } 53 } 54 55 // Index reads the index of the siva file from the provided reader 56 func (r *reader) Index() (Index, error) { 57 if r.getIndexFunc != nil { 58 return r.getIndexFunc() 59 } 60 61 if r.index == nil { 62 i, err := readIndex(r.r, r.offset) 63 if err != nil && err != ErrEmptyIndex { 64 return nil, err 65 } 66 67 index := OrderedIndex(i.filter()) 68 index.Sort() 69 r.index = Index(index) 70 } 71 72 return r.index, nil 73 } 74 75 // Get returns a new io.SectionReader allowing concurrent read access to the 76 // content of the read 77 func (r *reader) Get(e *IndexEntry) (*io.SectionReader, error) { 78 ra, ok := r.r.(io.ReaderAt) 79 if !ok { 80 return nil, ErrInvalidReaderAt 81 } 82 83 return io.NewSectionReader(ra, int64(e.absStart), int64(e.Size)), nil 84 } 85 86 // Seek seek the internal reader to the starting position of the content for the 87 // given IndexEntry 88 func (r *reader) Seek(e *IndexEntry) (int64, error) { 89 r.current = e 90 r.pending = e.Size 91 92 return r.r.Seek(int64(e.absStart), io.SeekStart) 93 } 94 95 // Read reads up to len(p) bytes, starting at the current position set by Seek 96 // and ending in the end of the content, retuning a io.EOF when its reached 97 func (r *reader) Read(p []byte) (n int, err error) { 98 if r.pending == 0 { 99 return 0, io.EOF 100 } 101 102 if uint64(len(p)) > r.pending { 103 p = p[0:r.pending] 104 } 105 106 n, err = r.r.Read(p) 107 r.pending -= uint64(n) 108 109 if err == io.EOF && r.pending > 0 { 110 err = io.ErrUnexpectedEOF 111 } 112 113 return 114 }