func (s *Slice) readFrom(r io.Reader) error {
	er := errorReader{r: r}
	s.refID = er.itf8()
	s.start = er.itf8()
	s.span = er.itf8()
	s.nRec = er.itf8()
	s.recCount = er.ltf8()
	s.blocks = er.itf8()
	s.blockIDs = er.itf8slice()
	s.embeddedRefID = er.itf8()
	_, err := io.ReadFull(&er, s.md5sum[:])
	if err != nil {
		return err
	}
	s.tags, err = ioutil.ReadAll(&er)
	return err
}
readFrom populates a Slice from the given io.Reader.
package cram
import (
	"bytes"
	"compress/bzip2"
	"compress/gzip"
	"encoding/binary"
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"io/ioutil"
	"os"
	"reflect"
	"github.com/ulikunitz/xz/lzma"
	"github.com/biogo/hts/cram/encoding/itf8"
	"github.com/biogo/hts/cram/encoding/ltf8"
	"github.com/biogo/hts/sam"
)
var cramEOFmarker = []byte{
	0x0f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,  
	0x0f, 0xe0, 0x45, 0x4f, 0x46, 0x00, 0x00, 0x00,  
	0x00, 0x01, 0x00, 0x05, 0xbd, 0xd9, 0x4f, 0x00,  
	0x01, 0x00, 0x06, 0x06, 0x01, 0x00, 0x01, 0x00,  
	0x01, 0x00, 0xee, 0x63, 0x01, 0x4b,    
}
var ErrNoEnd = errors.New("cram: cannot determine offset from end")
func HasEOF(r io.ReaderAt) (bool, error) {
	type sizer interface {
		Size() int64
	}
	type stater interface {
		Stat() (os.FileInfo, error)
	}
	type lenSeeker interface {
		io.Seeker
		Len() int
	}
	var size int64
	switch r := r.(type) {
	case sizer:
		size = r.Size()
	case stater:
		fi, err := r.Stat()
		if err != nil {
			return false, err
		}
		size = fi.Size()
	case lenSeeker:
		var err error
		size, err = r.Seek(0, 1)
		if err != nil {
			return false, err
		}
		size += int64(r.Len())
	default:
		return false, ErrNoEnd
	}
	b := make([]byte, len(cramEOFmarker))
	_, err := r.ReadAt(b, size-int64(len(cramEOFmarker)))
	if err != nil {
		return false, err
	}
	return bytes.Equal(b, cramEOFmarker), nil
}
type Reader struct {
	r io.Reader
	d definition
	c *Container
	err error
}
func NewReader(r io.Reader) (*Reader, error) {
	cr := Reader{r: r}
	err := cr.d.readFrom(r)
	if err != nil {
		return nil, err
	}
	return &cr, nil
}
func (r *Reader) Next() bool {
	if r.err != nil {
		return false
	}
	if r.c != nil {
		io.Copy(ioutil.Discard, r.c.blockData)
	}
	var c Container
	r.err = c.readFrom(r.r)
	r.c = &c
	return r.err == nil
}
func (r *Reader) Container() *Container {
	return r.c
}
func (r *Reader) Err() error {
	if r.err == io.EOF {
		return nil
	}
	return r.err
}
type definition struct {
	Magic   [4]byte `is:"CRAM"`
	Version [2]byte
	ID      [20]byte
}
func (d *definition) readFrom(r io.Reader) error {
	err := binary.Read(r, binary.LittleEndian, d)
	if err != nil {
		return err
	}
	magic := reflect.TypeOf(*d).Field(0).Tag.Get("is")
	if !bytes.Equal(d.Magic[:], []byte(magic)) {
		return fmt.Errorf("cram: not a cram file: magic bytes %q", d.Magic)
	}
	return nil
}
type Container struct {
	blockLen  int32
	refID     int32
	start     int32
	span      int32
	nRec      int32
	recCount  int64
	bases     int64
	blocks    int32
	landmarks []int32
	crc32     uint32
	blockData io.Reader
	block *Block
	err   error
}
func (c *Container) readFrom(r io.Reader) error {
	crc := crc32.NewIEEE()
	er := errorReader{r: io.TeeReader(r, crc)}
	var buf [4]byte
	io.ReadFull(&er, buf[:])
	c.blockLen = int32(binary.LittleEndian.Uint32(buf[:]))
	c.refID = er.itf8()
	c.start = er.itf8()
	c.span = er.itf8()
	c.nRec = er.itf8()
	c.recCount = er.ltf8()
	c.bases = er.ltf8()
	c.blocks = er.itf8()
	c.landmarks = er.itf8slice()
	sum := crc.Sum32()
	_, err := io.ReadFull(&er, buf[:])
	if err != nil {
		return err
	}
	c.crc32 = binary.LittleEndian.Uint32(buf[:])
	if c.crc32 != sum {
		return fmt.Errorf("cram: container crc32 mismatch got:0x%08x want:0x%08x", sum, c.crc32)
	}
	if er.err != nil {
		return er.err
	}
	c.blockData = &io.LimitedReader{R: r, N: int64(c.blockLen)}
	return nil
}
func (c *Container) Next() bool {
	if c.err != nil {
		return false
	}
	var b Block
	c.err = b.readFrom(c.blockData)
	if c.err == nil {
		c.block = &b
		return true
	}
	return false
}
func (c *Container) Block() *Block {
	return c.block
}
func (c *Container) Err() error {
	if c.err == io.EOF {
		return nil
	}
	return c.err
}
type Block struct {
	method         byte
	typ            byte
	contentID      int32
	compressedSize int32
	rawSize        int32
	blockData      []byte
	crc32          uint32
}
const (
	rawMethod = iota
	gzipMethod
	bzip2Method
	lzmaMethod
	ransMethod
)
const (
	fileHeader = iota
	compressionHeader
	mappedSliceHeader
	_  
	externalData
	coreData
)
func (b *Block) readFrom(r io.Reader) error {
	crc := crc32.NewIEEE()
	er := errorReader{r: io.TeeReader(r, crc)}
	var buf [4]byte
	io.ReadFull(&er, buf[:2])
	b.method = buf[0]
	b.typ = buf[1]
	b.contentID = er.itf8()
	b.compressedSize = er.itf8()
	b.rawSize = er.itf8()
	if b.method == rawMethod && b.compressedSize != b.rawSize {
		return fmt.Errorf("cram: compressed (%d) != raw (%d) size for raw method", b.compressedSize, b.rawSize)
	}
	b.blockData = make([]byte, b.compressedSize)
	_, err := io.ReadFull(&er, b.blockData)
	if err != nil {
		return err
	}
	sum := crc.Sum32()
	_, err = io.ReadFull(&er, buf[:])
	if err != nil {
		return err
	}
	b.crc32 = binary.LittleEndian.Uint32(buf[:])
	if b.crc32 != sum {
		return fmt.Errorf("cram: block crc32 mismatch got:0x%08x want:0x%08x", sum, b.crc32)
	}
	return nil
}
func (b *Block) Value() (interface{}, error) {
	switch b.typ {
	case fileHeader:
		var h sam.Header
		blockData, err := b.expandBlockdata()
		if err != nil {
			return nil, err
		}
		end := binary.LittleEndian.Uint32(blockData[:4])
		err = h.UnmarshalText(blockData[4 : 4+end])
		if err != nil {
			return nil, err
		}
		return &h, nil
	case mappedSliceHeader:
		var s Slice
		s.readFrom(bytes.NewReader(b.blockData))
		return &s, nil
	default:
		switch b.method {
		case gzipMethod, bzip2Method, lzmaMethod:
			var err error
			b.blockData, err = b.expandBlockdata()
			if err != nil {
				return nil, err
			}
			b.method |= 0x80
		default:
		}
		return b, nil
	}
}
func (b *Block) expandBlockdata() ([]byte, error) {
	switch b.method {
	default:
		panic(fmt.Sprintf("cram: unknown method: %v", b.method))
	case rawMethod:
		return b.blockData, nil
	case gzipMethod:
		gz, err := gzip.NewReader(bytes.NewReader(b.blockData))
		if err != nil {
			return nil, err
		}
		return ioutil.ReadAll(gz)
	case bzip2Method:
		return ioutil.ReadAll(bzip2.NewReader(bytes.NewReader(b.blockData)))
	case lzmaMethod:
		lz, err := lzma.NewReader(bytes.NewReader(b.blockData))
		if err != nil {
			return nil, err
		}
		return ioutil.ReadAll(lz)
	case ransMethod:
		return b.blockData, errors.New("unimplemented")
	}
}
type Slice struct {
	refID         int32
	start         int32
	span          int32
	nRec          int32
	recCount      int64
	blocks        int32
	blockIDs      []int32
	embeddedRefID int32
	md5sum        [16]byte
	tags          []byte
}