// Read reads actual data from the xz stream. func (r *streamReader) Read(p []byte) (n int, err error) { for n < len(p) { if r.br == nil { bh, hlen, err := readBlockHeader(r.xz) if err != nil { if err == errIndexIndicator { if err = r.readTail(); err != nil { return n, err } return n, io.EOF } return n, err } xlog.Debugf("block %v", *bh) r.br, err = r.ReaderConfig.newBlockReader(r.xz, bh, hlen, r.newHash()) if err != nil { return n, err } } k, err := r.br.Read(p[n:]) n += k if err != nil { if err == io.EOF { r.index = append(r.index, r.br.record()) r.br = nil } else { return n, err } } } return n, nil }
// newStreamReader creates a new xz stream reader using the given configuration // parameters. NewReader reads and checks the header of the xz stream. func (c ReaderConfig) newStreamReader(xz io.Reader) (r *streamReader, err error) { if err = c.Verify(); err != nil { return nil, err } data := make([]byte, HeaderLen) if _, err := io.ReadFull(xz, data[:4]); err != nil { return nil, err } if bytes.Equal(data[:4], []byte{0, 0, 0, 0}) { return nil, errPadding } if _, err = io.ReadFull(xz, data[4:]); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return nil, err } r = &streamReader{ ReaderConfig: c, xz: xz, index: make([]record, 0, 4), } if err = r.h.UnmarshalBinary(data); err != nil { return nil, err } xlog.Debugf("xz header %s", r.h) if r.newHash, err = newHashFunc(r.h.flags); err != nil { return nil, err } return r, nil }
// readTail reads the index body and the xz footer. func (r *streamReader) readTail() error { index, n, err := readIndexBody(r.xz) if err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return err } if len(index) != len(r.index) { return fmt.Errorf("xz: index length is %d; want %d", len(index), len(r.index)) } for i, rec := range r.index { if rec != index[i] { return fmt.Errorf("xz: record %d is %v; want %v", i, rec, index[i]) } } p := make([]byte, footerLen) if _, err = io.ReadFull(r.xz, p); err != nil { if err == io.EOF { err = io.ErrUnexpectedEOF } return err } var f footer if err = f.UnmarshalBinary(p); err != nil { return err } xlog.Debugf("xz footer %s", f) if f.flags != r.h.flags { return errors.New("xz: footer flags incorrect") } if f.indexSize != int64(n)+1 { return errors.New("xz: index size in footer wrong") } return nil }