main
Raw Download raw file
  1// Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package lzma
  6
  7import (
  8	"errors"
  9	"fmt"
 10	"io"
 11)
 12
 13// matcher is an interface that supports the identification of the next
 14// operation.
 15type matcher interface {
 16	io.Writer
 17	SetDict(d *encoderDict)
 18	NextOp(rep [4]uint32) operation
 19}
 20
 21// encoderDict provides the dictionary of the encoder. It includes an
 22// additional buffer atop of the actual dictionary.
 23type encoderDict struct {
 24	buf      buffer
 25	m        matcher
 26	head     int64
 27	capacity int
 28	// preallocated array
 29	data [maxMatchLen]byte
 30}
 31
 32// newEncoderDict creates the encoder dictionary. The argument bufSize
 33// defines the size of the additional buffer.
 34func newEncoderDict(dictCap, bufSize int, m matcher) (d *encoderDict, err error) {
 35	if !(1 <= dictCap && int64(dictCap) <= MaxDictCap) {
 36		return nil, errors.New(
 37			"lzma: dictionary capacity out of range")
 38	}
 39	if bufSize < 1 {
 40		return nil, errors.New(
 41			"lzma: buffer size must be larger than zero")
 42	}
 43	d = &encoderDict{
 44		buf:      *newBuffer(dictCap + bufSize),
 45		capacity: dictCap,
 46		m:        m,
 47	}
 48	m.SetDict(d)
 49	return d, nil
 50}
 51
 52// Discard discards n bytes. Note that n must not be larger than
 53// MaxMatchLen.
 54func (d *encoderDict) Discard(n int) {
 55	p := d.data[:n]
 56	k, _ := d.buf.Read(p)
 57	if k < n {
 58		panic(fmt.Errorf("lzma: can't discard %d bytes", n))
 59	}
 60	d.head += int64(n)
 61	d.m.Write(p)
 62}
 63
 64// Len returns the data available in the encoder dictionary.
 65func (d *encoderDict) Len() int {
 66	n := d.buf.Available()
 67	if int64(n) > d.head {
 68		return int(d.head)
 69	}
 70	return n
 71}
 72
 73// DictLen returns the actual length of data in the dictionary.
 74func (d *encoderDict) DictLen() int {
 75	if d.head < int64(d.capacity) {
 76		return int(d.head)
 77	}
 78	return d.capacity
 79}
 80
 81// Available returns the number of bytes that can be written by a
 82// following Write call.
 83func (d *encoderDict) Available() int {
 84	return d.buf.Available() - d.DictLen()
 85}
 86
 87// Write writes data into the dictionary buffer. Note that the position
 88// of the dictionary head will not be moved. If there is not enough
 89// space in the buffer ErrNoSpace will be returned.
 90func (d *encoderDict) Write(p []byte) (n int, err error) {
 91	m := d.Available()
 92	if len(p) > m {
 93		p = p[:m]
 94		err = ErrNoSpace
 95	}
 96	var e error
 97	if n, e = d.buf.Write(p); e != nil {
 98		err = e
 99	}
100	return n, err
101}
102
103// Pos returns the position of the head.
104func (d *encoderDict) Pos() int64 { return d.head }
105
106// ByteAt returns the byte at the given distance.
107func (d *encoderDict) ByteAt(distance int) byte {
108	if !(0 < distance && distance <= d.Len()) {
109		return 0
110	}
111	i := d.buf.rear - distance
112	if i < 0 {
113		i += len(d.buf.data)
114	}
115	return d.buf.data[i]
116}
117
118// CopyN copies the last n bytes from the dictionary into the provided
119// writer. This is used for copying uncompressed data into an
120// uncompressed segment.
121func (d *encoderDict) CopyN(w io.Writer, n int) (written int, err error) {
122	if n <= 0 {
123		return 0, nil
124	}
125	m := d.Len()
126	if n > m {
127		n = m
128		err = ErrNoSpace
129	}
130	i := d.buf.rear - n
131	var e error
132	if i < 0 {
133		i += len(d.buf.data)
134		if written, e = w.Write(d.buf.data[i:]); e != nil {
135			return written, e
136		}
137		i = 0
138	}
139	var k int
140	k, e = w.Write(d.buf.data[i:d.buf.rear])
141	written += k
142	if e != nil {
143		err = e
144	}
145	return written, err
146}
147
148// Buffered returns the number of bytes in the buffer.
149func (d *encoderDict) Buffered() int { return d.buf.Buffered() }