Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ReaderAt #31

Closed
wants to merge 14 commits into from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ cmd/xb/xb

# default compression test file
enwik8*
/fox
42 changes: 32 additions & 10 deletions format.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func newHashFunc(flags byte) (newHash func() hash.Hash, err error) {
return
}

// header provides the actual content of the xz file header: the flags.
type header struct {
// streamHeader provides the actual content of the xz stream: the flags.
type streamHeader struct {
flags byte
}

Expand All @@ -112,18 +112,36 @@ var errHeaderMagic = errors.New("xz: invalid header magic bytes")
// ValidHeader checks whether data is a correct xz file header. The
// length of data must be HeaderLen.
func ValidHeader(data []byte) bool {
var h header
var h streamHeader
err := h.UnmarshalBinary(data)
return err == nil
}

// String returns a string representation of the flags.
func (h header) String() string {
func (h streamHeader) String() string {
return flagString(h.flags)
}

func (h *streamHeader) UnmarshalReader(xz io.Reader) error {
data := make([]byte, HeaderLen)
if _, err := io.ReadFull(xz, data[:4]); err != nil {
return err
}
if bytes.Equal(data[:4], []byte{0, 0, 0, 0}) {
return errPadding
}
if _, err := io.ReadFull(xz, data[4:]); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return err
}

return h.UnmarshalBinary(data)
}

// UnmarshalBinary reads header from the provided data slice.
func (h *header) UnmarshalBinary(data []byte) error {
func (h *streamHeader) UnmarshalBinary(data []byte) error {
// header length
if len(data) != HeaderLen {
return errors.New("xz: wrong file header length")
Expand Down Expand Up @@ -155,7 +173,7 @@ func (h *header) UnmarshalBinary(data []byte) error {
}

// MarshalBinary generates the xz file header.
func (h *header) MarshalBinary() (data []byte, err error) {
func (h *streamHeader) MarshalBinary() (data []byte, err error) {
if err = verifyFlags(h.flags); err != nil {
return nil, err
}
Expand Down Expand Up @@ -193,7 +211,7 @@ func (f footer) String() string {
// Minimum and maximum for the size of the index (backward size).
const (
minIndexSize = 4
maxIndexSize = (1 << 32) * 4
maxIndexSize = 1 << 32 * 4
)

// MarshalBinary converts footer values into an xz file footer. Note
Expand All @@ -213,7 +231,7 @@ func (f *footer) MarshalBinary() (data []byte, err error) {
data = make([]byte, footerLen)

// backward size (index size)
s := (f.indexSize / 4) - 1
s := f.indexSize/4 - 1
putUint32LE(data[4:], uint32(s))
// flags
data[9] = f.flags
Expand All @@ -228,8 +246,7 @@ func (f *footer) MarshalBinary() (data []byte, err error) {
return data, nil
}

// UnmarshalBinary sets the footer value by unmarshalling an xz file
// footer.
// UnmarshalBinary sets the footer value by unmarshalling an xz file footer.
func (f *footer) UnmarshalBinary(data []byte) error {
if len(data) != footerLen {
return errors.New("xz: wrong footer length")
Expand Down Expand Up @@ -627,6 +644,11 @@ func (rec *record) MarshalBinary() (data []byte, err error) {
return p[:n], nil
}

// paddedLen returns the padded length of the compressed record.
func (rec *record) paddedLen() int64 {
return int64(padLen(rec.unpaddedSize)) + rec.unpaddedSize
}

// writeIndex writes the index, a sequence of records.
func writeIndex(w io.Writer, index []record) (n int64, err error) {
crc := crc32.NewIEEE()
Expand Down
4 changes: 2 additions & 2 deletions format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
)

func TestHeader(t *testing.T) {
h := header{flags: CRC32}
h := streamHeader{flags: CRC32}
data, err := h.MarshalBinary()
if err != nil {
t.Fatalf("MarshalBinary error %s", err)
}
var g header
var g streamHeader
if err = g.UnmarshalBinary(data); err != nil {
t.Fatalf("UnmarshalBinary error %s", err)
}
Expand Down
47 changes: 23 additions & 24 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type streamReader struct {
xz io.Reader
br *blockReader
newHash func() hash.Hash
h header
h streamHeader
index []record
}

Expand Down Expand Up @@ -137,27 +137,17 @@ 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 {

if err := r.h.UnmarshalReader(xz); 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
Expand Down Expand Up @@ -188,15 +178,8 @@ func (r *streamReader) readTail() error {
}
}

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 {
f, err := readFooter(r.xz)
if err != nil {
return err
}
xlog.Debugf("xz footer %s", f)
Expand All @@ -209,6 +192,22 @@ func (r *streamReader) readTail() error {
return nil
}

func readFooter(r io.Reader) (*footer, error) {
p := make([]byte, footerLen)
if _, err := io.ReadFull(r, p); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
return nil, err
}
var f footer
if err := f.UnmarshalBinary(p); err != nil {
return nil, err
}

return &f, nil
}

// Read reads actual data from the xz stream.
func (r *streamReader) Read(p []byte) (n int, err error) {
for n < len(p) {
Expand Down
Loading