func (s *Scanner) Checksum() (plumbing.Hash, error) {
	err := s.discardObjectIfNeeded()
	if err != nil {
		return plumbing.ZeroHash, err
	}
	return binary.ReadHash(s.r)
}
Checksum returns the checksum of the packfile
package packfile
import (
	"bufio"
	"bytes"
	"compress/zlib"
	"fmt"
	"hash"
	"hash/crc32"
	"io"
	stdioutil "io/ioutil"
	"sync"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/utils/binary"
	"gopkg.in/src-d/go-git.v4/utils/ioutil"
)
var (
	ErrEmptyPackfile = NewError("empty packfile")
	ErrBadSignature = NewError("malformed pack file signature")
	ErrUnsupportedVersion = NewError("unsupported packfile version")
	ErrSeekNotSupported = NewError("not seek support")
)
type ObjectHeader struct {
	Type            plumbing.ObjectType
	Offset          int64
	Length          int64
	Reference       plumbing.Hash
	OffsetReference int64
}
type Scanner struct {
	r   reader
	zr  readerResetter
	crc hash.Hash32
	pendingObject    *ObjectHeader
	version, objects uint32
	IsSeekable bool
}
func NewScanner(r io.Reader) *Scanner {
	seeker, ok := r.(io.ReadSeeker)
	if !ok {
		seeker = &trackableReader{Reader: r}
	}
	crc := crc32.NewIEEE()
	return &Scanner{
		r: &teeReader{
			newByteReadSeeker(seeker),
			crc,
		},
		crc:        crc,
		IsSeekable: ok,
	}
}
func (s *Scanner) Header() (version, objects uint32, err error) {
	if s.version != 0 {
		return s.version, s.objects, nil
	}
	sig, err := s.readSignature()
	if err != nil {
		if err == io.EOF {
			err = ErrEmptyPackfile
		}
		return
	}
	if !s.isValidSignature(sig) {
		err = ErrBadSignature
		return
	}
	version, err = s.readVersion()
	s.version = version
	if err != nil {
		return
	}
	if !s.isSupportedVersion(version) {
		err = ErrUnsupportedVersion.AddDetails("%d", version)
		return
	}
	objects, err = s.readCount()
	s.objects = objects
	return
}
func (s *Scanner) readSignature() ([]byte, error) {
	var sig = make([]byte, 4)
	if _, err := io.ReadFull(s.r, sig); err != nil {
		return []byte{}, err
	}
	return sig, nil
}
func (s *Scanner) isValidSignature(sig []byte) bool {
	return bytes.Equal(sig, signature)
}
func (s *Scanner) readVersion() (uint32, error) {
	return binary.ReadUint32(s.r)
}
func (s *Scanner) isSupportedVersion(v uint32) bool {
	return v == VersionSupported
}
func (s *Scanner) readCount() (uint32, error) {
	return binary.ReadUint32(s.r)
}
func (s *Scanner) NextObjectHeader() (*ObjectHeader, error) {
	if err := s.doPending(); err != nil {
		return nil, err
	}
	s.crc.Reset()
	h := &ObjectHeader{}
	s.pendingObject = h
	var err error
	h.Offset, err = s.r.Seek(0, io.SeekCurrent)
	if err != nil {
		return nil, err
	}
	h.Type, h.Length, err = s.readObjectTypeAndLength()
	if err != nil {
		return nil, err
	}
	switch h.Type {
	case plumbing.OFSDeltaObject:
		no, err := binary.ReadVariableWidthInt(s.r)
		if err != nil {
			return nil, err
		}
		h.OffsetReference = h.Offset - no
	case plumbing.REFDeltaObject:
		var err error
		h.Reference, err = binary.ReadHash(s.r)
		if err != nil {
			return nil, err
		}
	}
	return h, nil
}
func (s *Scanner) doPending() error {
	if s.version == 0 {
		var err error
		s.version, s.objects, err = s.Header()
		if err != nil {
			return err
		}
	}
	return s.discardObjectIfNeeded()
}
func (s *Scanner) discardObjectIfNeeded() error {
	if s.pendingObject == nil {
		return nil
	}
	h := s.pendingObject
	n, _, err := s.NextObject(stdioutil.Discard)
	if err != nil {
		return err
	}
	if n != h.Length {
		return fmt.Errorf(
			"error discarding object, discarded %d, expected %d",
			n, h.Length,
		)
	}
	return nil
}
func (s *Scanner) readObjectTypeAndLength() (plumbing.ObjectType, int64, error) {
	t, c, err := s.readType()
	if err != nil {
		return t, 0, err
	}
	l, err := s.readLength(c)
	return t, l, err
}
func (s *Scanner) readType() (plumbing.ObjectType, byte, error) {
	var c byte
	var err error
	if c, err = s.r.ReadByte(); err != nil {
		return plumbing.ObjectType(0), 0, err
	}
	typ := parseType(c)
	return typ, c, nil
}
func parseType(b byte) plumbing.ObjectType {
	return plumbing.ObjectType((b & maskType) >> firstLengthBits)
}
func (s *Scanner) readLength(first byte) (int64, error) {
	length := int64(first & maskFirstLength)
	c := first
	shift := firstLengthBits
	var err error
	for c&maskContinue > 0 {
		if c, err = s.r.ReadByte(); err != nil {
			return 0, err
		}
		length += int64(c&maskLength) << shift
		shift += lengthBits
	}
	return length, nil
}
func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err error) {
	defer s.crc.Reset()
	s.pendingObject = nil
	written, err = s.copyObject(w)
	crc32 = s.crc.Sum32()
	return
}
func (s *Scanner) copyObject(w io.Writer) (n int64, err error) {
	if s.zr == nil {
		zr, err := zlib.NewReader(s.r)
		if err != nil {
			return 0, fmt.Errorf("zlib initialization error: %s", err)
		}
		s.zr = zr.(readerResetter)
	} else {
		if err := s.zr.Reset(s.r, nil); err != nil {
			return 0, fmt.Errorf("zlib reset error: %s", err)
		}
	}
	defer ioutil.CheckClose(s.zr, &err)
	buf := byteSlicePool.Get().([]byte)
	n, err = io.CopyBuffer(w, s.zr, buf)
	byteSlicePool.Put(buf)
	return
}
var byteSlicePool = sync.Pool{
	New: func() interface{} {
		return make([]byte, 32*1024)
	},
}
func (s *Scanner) SeekFromStart(offset int64) (previous int64, err error) {
	if s.version == 0 {
		s.version = VersionSupported
	}
	previous, err = s.r.Seek(0, io.SeekCurrent)
	if err != nil {
		return -1, err
	}
	_, err = s.r.Seek(offset, io.SeekStart)
	return previous, err
}