func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
	var (
		cntNewline int64
		buf        bytes.Buffer
		blk        block
	)
	feedTokens := func(n int64) error {
		for cntNewline < n {
			if _, err := mustReadFull(r, blk[:]); err != nil {
				return err
			}
			buf.Write(blk[:])
			for _, c := range blk {
				if c == '\n' {
					cntNewline++
				}
			}
		}
		return nil
	}
	nextToken := func() string {
		cntNewline--
		tok, _ := buf.ReadString('\n')
		return strings.TrimRight(tok, "\n")
	}
	if err := feedTokens(1); err != nil {
		return nil, err
	}
	numEntries, err := strconv.ParseInt(nextToken(), 10, 0)  
	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
		return nil, ErrHeader
	}
	if err := feedTokens(2 * numEntries); err != nil {
		return nil, err
	}
	spd := make(sparseDatas, 0, numEntries)
	for i := int64(0); i < numEntries; i++ {
		offset, err1 := strconv.ParseInt(nextToken(), 10, 64)
		length, err2 := strconv.ParseInt(nextToken(), 10, 64)
		if err1 != nil || err2 != nil {
			return nil, ErrHeader
		}
		spd = append(spd, sparseEntry{Offset: offset, Length: length})
	}
	return spd, nil
}
readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
version 1.0. The format of the sparse map consists of a series of
newline-terminated numeric fields. The first field is the number of entries
and is always present. Following this are the entries, consisting of two
fields (offset, length). This function must stop reading at the end
boundary of the block containing the last newline.

Note that the GNU manual says that numeric values should be encoded in octal
format. However, the GNU tar utility itself outputs these values in decimal.
As such, this library treats values as being encoded in decimal.
package tar
import (
	"bytes"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"time"
)
type Reader struct {
	r    io.Reader
	pad  int64       
	curr fileReader  
	blk  block       
	err error
	RawAccounting bool           
	rawBytes      *bytes.Buffer  
}
type fileReader interface {
	io.Reader
	fileState
	WriteTo(io.Writer) (int64, error)
}
func (tr *Reader) RawBytes() []byte {
	if !tr.RawAccounting {
		return nil
	}
	if tr.rawBytes == nil {
		tr.rawBytes = bytes.NewBuffer(nil)
	}
	defer tr.rawBytes.Reset()  
	return tr.rawBytes.Bytes()
}
func NewReader(r io.Reader) *Reader {
	return &Reader{r: r, curr: &regFileReader{r, 0}}
}
func (tr *Reader) Next() (*Header, error) {
	if tr.err != nil {
		return nil, tr.err
	}
	hdr, err := tr.next()
	tr.err = err
	return hdr, err
}
func (tr *Reader) next() (*Header, error) {
	var paxHdrs map[string]string
	var gnuLongName, gnuLongLink string
	if tr.RawAccounting {
		if tr.rawBytes == nil {
			tr.rawBytes = bytes.NewBuffer(nil)
		} else {
			tr.rawBytes.Reset()
		}
	}
	format := FormatUSTAR | FormatPAX | FormatGNU
	for {
		if err := discard(tr, tr.curr.PhysicalRemaining()); err != nil {
			return nil, err
		}
		n, err := tryReadFull(tr.r, tr.blk[:tr.pad])
		if err != nil {
			return nil, err
		}
		if tr.RawAccounting {
			tr.rawBytes.Write(tr.blk[:n])
		}
		tr.pad = 0
		hdr, rawHdr, err := tr.readHeader()
		if err != nil {
			return nil, err
		}
		if err := tr.handleRegularFile(hdr); err != nil {
			return nil, err
		}
		format.mayOnlyBe(hdr.Format)
		switch hdr.Typeflag {
		case TypeXHeader, TypeXGlobalHeader:
			format.mayOnlyBe(FormatPAX)
			paxHdrs, err = parsePAX(tr)
			if err != nil {
				return nil, err
			}
			if hdr.Typeflag == TypeXGlobalHeader {
				mergePAX(hdr, paxHdrs)
				return &Header{
					Name:       hdr.Name,
					Typeflag:   hdr.Typeflag,
					Xattrs:     hdr.Xattrs,
					PAXRecords: hdr.PAXRecords,
					Format:     format,
				}, nil
			}
			continue  
		case TypeGNULongName, TypeGNULongLink:
			format.mayOnlyBe(FormatGNU)
			realname, err := ioutil.ReadAll(tr)
			if err != nil {
				return nil, err
			}
			if tr.RawAccounting {
				tr.rawBytes.Write(realname)
			}
			var p parser
			switch hdr.Typeflag {
			case TypeGNULongName:
				gnuLongName = p.parseString(realname)
			case TypeGNULongLink:
				gnuLongLink = p.parseString(realname)
			}
			continue  
		default:
			if err := mergePAX(hdr, paxHdrs); err != nil {
				return nil, err
			}
			if gnuLongName != "" {
				hdr.Name = gnuLongName
			}
			if gnuLongLink != "" {
				hdr.Linkname = gnuLongLink
			}
			if hdr.Typeflag == TypeRegA {
				if strings.HasSuffix(hdr.Name, "/") {
					hdr.Typeflag = TypeDir  
				} else {
					hdr.Typeflag = TypeReg
				}
			}
			if err := tr.handleRegularFile(hdr); err != nil {
				return nil, err
			}
			if err := tr.handleSparseFile(hdr, rawHdr); err != nil {
				return nil, err
			}
			if format.has(FormatUSTAR) && format.has(FormatPAX) {
				format.mayOnlyBe(FormatUSTAR)
			}
			hdr.Format = format
			return hdr, nil  
		}
	}
}
func (tr *Reader) handleRegularFile(hdr *Header) error {
	nb := hdr.Size
	if isHeaderOnlyType(hdr.Typeflag) {
		nb = 0
	}
	if nb < 0 {
		return ErrHeader
	}
	tr.pad = blockPadding(nb)
	tr.curr = &regFileReader{r: tr.r, nb: nb}
	return nil
}
func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block) error {
	var spd sparseDatas
	var err error
	if hdr.Typeflag == TypeGNUSparse {
		spd, err = tr.readOldGNUSparseMap(hdr, rawHdr)
	} else {
		spd, err = tr.readGNUSparsePAXHeaders(hdr)
	}
	if err == nil && spd != nil {
		if isHeaderOnlyType(hdr.Typeflag) || !validateSparseEntries(spd, hdr.Size) {
			return ErrHeader
		}
		sph := invertSparseEntries(spd, hdr.Size)
		tr.curr = &sparseFileReader{tr.curr, sph, 0}
	}
	return err
}
func (tr *Reader) readGNUSparsePAXHeaders(hdr *Header) (sparseDatas, error) {
	var is1x0 bool
	major, minor := hdr.PAXRecords[paxGNUSparseMajor], hdr.PAXRecords[paxGNUSparseMinor]
	switch {
	case major == "0" && (minor == "0" || minor == "1"):
		is1x0 = false
	case major == "1" && minor == "0":
		is1x0 = true
	case major != "" || minor != "":
		return nil, nil  
	case hdr.PAXRecords[paxGNUSparseMap] != "":
		is1x0 = false  
	default:
		return nil, nil  
	}
	hdr.Format.mayOnlyBe(FormatPAX)
	if name := hdr.PAXRecords[paxGNUSparseName]; name != "" {
		hdr.Name = name
	}
	size := hdr.PAXRecords[paxGNUSparseSize]
	if size == "" {
		size = hdr.PAXRecords[paxGNUSparseRealSize]
	}
	if size != "" {
		n, err := strconv.ParseInt(size, 10, 64)
		if err != nil {
			return nil, ErrHeader
		}
		hdr.Size = n
	}
	if is1x0 {
		return readGNUSparseMap1x0(tr.curr)
	}
	return readGNUSparseMap0x1(hdr.PAXRecords)
}
func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
	for k, v := range paxHdrs {
		if v == "" {
			continue  
		}
		var id64 int64
		switch k {
		case paxPath:
			hdr.Name = v
		case paxLinkpath:
			hdr.Linkname = v
		case paxUname:
			hdr.Uname = v
		case paxGname:
			hdr.Gname = v
		case paxUid:
			id64, err = strconv.ParseInt(v, 10, 64)
			hdr.Uid = int(id64)  
		case paxGid:
			id64, err = strconv.ParseInt(v, 10, 64)
			hdr.Gid = int(id64)  
		case paxAtime:
			hdr.AccessTime, err = parsePAXTime(v)
		case paxMtime:
			hdr.ModTime, err = parsePAXTime(v)
		case paxCtime:
			hdr.ChangeTime, err = parsePAXTime(v)
		case paxSize:
			hdr.Size, err = strconv.ParseInt(v, 10, 64)
		default:
			if strings.HasPrefix(k, paxSchilyXattr) {
				if hdr.Xattrs == nil {
					hdr.Xattrs = make(map[string]string)
				}
				hdr.Xattrs[k[len(paxSchilyXattr):]] = v
			}
		}
		if err != nil {
			return ErrHeader
		}
	}
	hdr.PAXRecords = paxHdrs
	return nil
}
func parsePAX(r io.Reader) (map[string]string, error) {
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	if tr, ok := r.(*Reader); ok && tr.RawAccounting {
		if _, err = tr.rawBytes.Write(buf); err != nil {
			return nil, err
		}
	}
	sbuf := string(buf)
	var sparseMap []string
	paxHdrs := make(map[string]string)
	for len(sbuf) > 0 {
		key, value, residual, err := parsePAXRecord(sbuf)
		if err != nil {
			return nil, ErrHeader
		}
		sbuf = residual
		switch key {
		case paxGNUSparseOffset, paxGNUSparseNumBytes:
			if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
				(len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
				strings.Contains(value, ",") {
				return nil, ErrHeader
			}
			sparseMap = append(sparseMap, value)
		default:
			paxHdrs[key] = value
		}
	}
	if len(sparseMap) > 0 {
		paxHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
	}
	return paxHdrs, nil
}
func (tr *Reader) readHeader() (*Header, *block, error) {
	n, err := io.ReadFull(tr.r, tr.blk[:])
	if tr.RawAccounting && (err == nil || err == io.EOF) {
		tr.rawBytes.Write(tr.blk[:n])
	}
	if err != nil {
		return nil, nil, err  
	}
	if bytes.Equal(tr.blk[:], zeroBlock[:]) {
		n, err = io.ReadFull(tr.r, tr.blk[:])
		if tr.RawAccounting && (err == nil || err == io.EOF) {
			tr.rawBytes.Write(tr.blk[:n])
		}
		if err != nil {
			return nil, nil, err  
		}
		if bytes.Equal(tr.blk[:], zeroBlock[:]) {
			return nil, nil, io.EOF  
		}
		return nil, nil, ErrHeader  
	}
	format := tr.blk.GetFormat()
	if format == FormatUnknown {
		return nil, nil, ErrHeader
	}
	var p parser
	hdr := new(Header)
	v7 := tr.blk.V7()
	hdr.Typeflag = v7.TypeFlag()[0]
	hdr.Name = p.parseString(v7.Name())
	hdr.Linkname = p.parseString(v7.LinkName())
	hdr.Size = p.parseNumeric(v7.Size())
	hdr.Mode = p.parseNumeric(v7.Mode())
	hdr.Uid = int(p.parseNumeric(v7.UID()))
	hdr.Gid = int(p.parseNumeric(v7.GID()))
	hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
	if format > formatV7 {
		ustar := tr.blk.USTAR()
		hdr.Uname = p.parseString(ustar.UserName())
		hdr.Gname = p.parseString(ustar.GroupName())
		hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
		hdr.Devminor = p.parseNumeric(ustar.DevMinor())
		var prefix string
		switch {
		case format.has(FormatUSTAR | FormatPAX):
			hdr.Format = format
			ustar := tr.blk.USTAR()
			prefix = p.parseString(ustar.Prefix())
			notASCII := func(r rune) bool { return r >= 0x80 }
			if bytes.IndexFunc(tr.blk[:], notASCII) >= 0 {
				hdr.Format = FormatUnknown  
			}
			nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
			if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) &&
				nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
				hdr.Format = FormatUnknown  
			}
		case format.has(formatSTAR):
			star := tr.blk.STAR()
			prefix = p.parseString(star.Prefix())
			hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
			hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
		case format.has(FormatGNU):
			hdr.Format = format
			var p2 parser
			gnu := tr.blk.GNU()
			if b := gnu.AccessTime(); b[0] != 0 {
				hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
			}
			if b := gnu.ChangeTime(); b[0] != 0 {
				hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
			}
			if p2.err != nil {
				hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
				ustar := tr.blk.USTAR()
				if s := p.parseString(ustar.Prefix()); isASCII(s) {
					prefix = s
				}
				hdr.Format = FormatUnknown  
			}
		}
		if len(prefix) > 0 {
			hdr.Name = prefix + "/" + hdr.Name
		}
	}
	return hdr, &tr.blk, p.err
}
func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, error) {
	if blk.GetFormat() != FormatGNU {
		return nil, ErrHeader
	}
	hdr.Format.mayOnlyBe(FormatGNU)
	var p parser
	hdr.Size = p.parseNumeric(blk.GNU().RealSize())
	if p.err != nil {
		return nil, p.err
	}
	s := blk.GNU().Sparse()
	spd := make(sparseDatas, 0, s.MaxEntries())
	for {
		for i := 0; i < s.MaxEntries(); i++ {
			if s.Entry(i).Offset()[0] == 0x00 {
				break  
			}
			offset := p.parseNumeric(s.Entry(i).Offset())
			length := p.parseNumeric(s.Entry(i).Length())
			if p.err != nil {
				return nil, p.err
			}
			spd = append(spd, sparseEntry{Offset: offset, Length: length})
		}
		if s.IsExtended()[0] > 0 {
			if _, err := mustReadFull(tr.r, blk[:]); err != nil {
				return nil, err
			}
			if tr.RawAccounting {
				tr.rawBytes.Write(blk[:])
			}
			s = blk.Sparse()
			continue
		}
		return spd, nil  
	}
}