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

Factor out xzinternals #29

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions filter/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package filter

import (
"errors"
"io"

"github.com/ulikunitz/xz/lzma"
)

// ReaderConfig defines the parameters for the xz reader. The
// SingleStream parameter requests the reader to assume that the
// underlying stream contains only a single stream.
type ReaderConfig struct {
DictCap int
}

// WriterConfig defines the configuration parameter for a writer.
type WriterConfig struct {
Properties *lzma.Properties
DictCap int
BufSize int

// match algorithm
Matcher lzma.MatchAlgorithm
}

// Filter represents a filter in the block header.
type Filter interface {
ID() uint64
UnmarshalBinary(data []byte) error
MarshalBinary() (data []byte, err error)
Reader(r io.Reader, c *ReaderConfig) (fr io.Reader, err error)
WriteCloser(w io.WriteCloser, c *WriterConfig) (fw io.WriteCloser, err error)
// filter must be last filter
last() bool
}

func NewFilterReader(c *ReaderConfig, r io.Reader, f []Filter) (fr io.Reader,
err error) {

if err = VerifyFilters(f); err != nil {
return nil, err
}

fr = r
for i := len(f) - 1; i >= 0; i-- {
fr, err = f[i].Reader(fr, c)
if err != nil {
return nil, err
}
}
return fr, nil
}

// newFilterWriteCloser converts a filter list into a WriteCloser that
// can be used by a blockWriter.
func NewFilterWriteCloser(filterWriteConfig *WriterConfig, w io.Writer, f []Filter) (fw io.WriteCloser, err error) {

if err = VerifyFilters(f); err != nil {
return nil, err
}
fw = nopWriteCloser(w)
for i := len(f) - 1; i >= 0; i-- {
fw, err = f[i].WriteCloser(fw, filterWriteConfig)
if err != nil {
return nil, err
}
}
return fw, nil
}

// VerifyFilters checks the filter list for the length and the right
// sequence of filters.
func VerifyFilters(f []Filter) error {
if len(f) == 0 {
return errors.New("xz: no filters")
}
if len(f) > 4 {
return errors.New("xz: more than four filters")
}
for _, g := range f[:len(f)-1] {
if g.last() {
return errors.New("xz: last filter is not last")
}
}
if !f[len(f)-1].last() {
return errors.New("xz: wrong last filter")
}
return nil
}

// nopWCloser implements a WriteCloser with a Close method not doing
// anything.
type nopWCloser struct {
io.Writer
}

// Close returns nil and doesn't do anything else.
func (c nopWCloser) Close() error {
return nil
}

// nopWriteCloser converts the Writer into a WriteCloser with a Close
// function that does nothing beside returning nil.
func nopWriteCloser(w io.Writer) io.WriteCloser {
return nopWCloser{w}
}
42 changes: 24 additions & 18 deletions lzmafilter.go → filter/lzmafilter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xz
package filter

import (
"errors"
Expand All @@ -14,37 +14,43 @@ import (

// LZMA filter constants.
const (
lzmaFilterID = 0x21
lzmaFilterLen = 3
LZMAFilterID = 0x21
LZMAFilterLen = 3
)

// lzmaFilter declares the LZMA2 filter information stored in an xz
func NewLZMAFilter(cap int64) *LZMAFilter {
return &LZMAFilter{dictCap: cap}
}

// LZMAFilter declares the LZMA2 filter information stored in an xz
// block header.
type lzmaFilter struct {
type LZMAFilter struct {
dictCap int64
}

func (f LZMAFilter) GetDictCap() int64 { return f.dictCap }

// String returns a representation of the LZMA filter.
func (f lzmaFilter) String() string {
func (f LZMAFilter) String() string {
return fmt.Sprintf("LZMA dict cap %#x", f.dictCap)
}

// id returns the ID for the LZMA2 filter.
func (f lzmaFilter) id() uint64 { return lzmaFilterID }
func (f LZMAFilter) ID() uint64 { return LZMAFilterID }

// MarshalBinary converts the lzmaFilter in its encoded representation.
func (f lzmaFilter) MarshalBinary() (data []byte, err error) {
// MarshalBinary converts the LZMAFilter in its encoded representation.
func (f LZMAFilter) MarshalBinary() (data []byte, err error) {
c := lzma.EncodeDictCap(f.dictCap)
return []byte{lzmaFilterID, 1, c}, nil
return []byte{LZMAFilterID, 1, c}, nil
}

// UnmarshalBinary unmarshals the given data representation of the LZMA2
// filter.
func (f *lzmaFilter) UnmarshalBinary(data []byte) error {
if len(data) != lzmaFilterLen {
func (f *LZMAFilter) UnmarshalBinary(data []byte) error {
if len(data) != LZMAFilterLen {
return errors.New("xz: data for LZMA2 filter has wrong length")
}
if data[0] != lzmaFilterID {
if data[0] != LZMAFilterID {
return errors.New("xz: wrong LZMA2 filter id")
}
if data[1] != 1 {
Expand All @@ -59,8 +65,8 @@ func (f *lzmaFilter) UnmarshalBinary(data []byte) error {
return nil
}

// reader creates a new reader for the LZMA2 filter.
func (f lzmaFilter) reader(r io.Reader, c *ReaderConfig) (fr io.Reader,
// Reader creates a new reader for the LZMA2 filter.
func (f LZMAFilter) Reader(r io.Reader, c *ReaderConfig) (fr io.Reader,
err error) {

config := new(lzma.Reader2Config)
Expand All @@ -83,8 +89,8 @@ func (f lzmaFilter) reader(r io.Reader, c *ReaderConfig) (fr io.Reader,
return fr, nil
}

// writeCloser creates a io.WriteCloser for the LZMA2 filter.
func (f lzmaFilter) writeCloser(w io.WriteCloser, c *WriterConfig,
// WriteCloser creates a io.WriteCloser for the LZMA2 filter.
func (f LZMAFilter) WriteCloser(w io.WriteCloser, c *WriterConfig,
) (fw io.WriteCloser, err error) {
config := new(lzma.Writer2Config)
if c != nil {
Expand Down Expand Up @@ -114,4 +120,4 @@ func (f lzmaFilter) writeCloser(w io.WriteCloser, c *WriterConfig,

// last returns true, because an LZMA2 filter must be the last filter in
// the filter list.
func (f lzmaFilter) last() bool { return true }
func (f LZMAFilter) last() bool { return true }
Loading