github.com/bodgit/sevenzip@v1.5.1/internal/lzma/reader.go (about)

     1  package lzma
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"io"
     8  
     9  	"github.com/ulikunitz/xz/lzma"
    10  )
    11  
    12  type readCloser struct {
    13  	c io.Closer
    14  	r io.Reader
    15  }
    16  
    17  func (rc *readCloser) Close() error {
    18  	var err error
    19  	if rc.c != nil {
    20  		err = rc.c.Close()
    21  		rc.c, rc.r = nil, nil
    22  	}
    23  
    24  	return err
    25  }
    26  
    27  func (rc *readCloser) Read(p []byte) (int, error) {
    28  	if rc.r == nil {
    29  		return 0, errors.New("lzma: Read after Close")
    30  	}
    31  
    32  	return rc.r.Read(p)
    33  }
    34  
    35  // NewReader returns a new LZMA io.ReadCloser.
    36  func NewReader(p []byte, s uint64, readers []io.ReadCloser) (io.ReadCloser, error) {
    37  	if len(readers) != 1 {
    38  		return nil, errors.New("lzma: need exactly one reader")
    39  	}
    40  
    41  	h := bytes.NewBuffer(p)
    42  	_ = binary.Write(h, binary.LittleEndian, s)
    43  
    44  	lr, err := lzma.NewReader(multiReader(h, readers[0]))
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	return &readCloser{
    50  		c: readers[0],
    51  		r: lr,
    52  	}, nil
    53  }
    54  
    55  func multiReader(b *bytes.Buffer, rc io.ReadCloser) io.Reader {
    56  	mr := io.MultiReader(b, rc)
    57  
    58  	if br, ok := rc.(io.ByteReader); ok {
    59  		return &multiByteReader{
    60  			b:  b,
    61  			br: br,
    62  			mr: mr,
    63  		}
    64  	}
    65  
    66  	return mr
    67  }
    68  
    69  type multiByteReader struct {
    70  	b  *bytes.Buffer
    71  	br io.ByteReader
    72  	mr io.Reader
    73  }
    74  
    75  func (m *multiByteReader) ReadByte() (byte, error) {
    76  	if m.b.Len() > 0 {
    77  		return m.b.ReadByte()
    78  	}
    79  
    80  	return m.br.ReadByte()
    81  }
    82  
    83  func (m *multiByteReader) Read(p []byte) (n int, err error) {
    84  	return m.mr.Read(p)
    85  }