package zim import ( "io" "sync" "github.com/pkg/errors" ) type UncompressedBlobReader struct { reader *Reader blobStartOffset uint64 blobEndOffset uint64 blobSize int readOffset int blobData []byte loadBlobOnce sync.Once loadBlobErr error } // Size implements BlobReader. func (r *UncompressedBlobReader) Size() (int64, error) { return int64(r.blobEndOffset - r.blobStartOffset), nil } // Close implements io.ReadCloser. func (r *UncompressedBlobReader) Close() error { clear(r.blobData) return nil } // Read implements io.ReadCloser. func (r *UncompressedBlobReader) Read(p []byte) (n int, err error) { blobData, err := r.loadBlob() if err != nil { return 0, errors.WithStack(err) } chunkLength := len(p) remaining := int(len(blobData) - r.readOffset) if chunkLength > remaining { chunkLength = remaining } chunk := blobData[r.readOffset : r.readOffset+chunkLength] r.readOffset += chunkLength copy(p, chunk) if chunkLength == remaining { return chunkLength, io.EOF } return chunkLength, nil } func (r *UncompressedBlobReader) loadBlob() ([]byte, error) { r.loadBlobOnce.Do(func() { data := make([]byte, r.blobEndOffset-r.blobStartOffset) err := r.reader.readRange(int64(r.blobStartOffset), data) if err != nil { r.loadBlobErr = errors.WithStack(err) return } r.blobData = data }) if r.loadBlobErr != nil { return nil, errors.WithStack(r.loadBlobErr) } return r.blobData, nil } func NewUncompressedBlobReader(reader *Reader, blobStartOffset, blobEndOffset uint64, blobSize int) *UncompressedBlobReader { return &UncompressedBlobReader{ reader: reader, blobStartOffset: blobStartOffset, blobEndOffset: blobEndOffset, blobSize: blobSize, readOffset: 0, } } var _ BlobReader = &UncompressedBlobReader{}