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)
 11
 12// decoderDict provides the dictionary for the decoder. The whole
 13// dictionary is used as reader buffer.
 14type decoderDict struct {
 15	buf  buffer
 16	head int64
 17}
 18
 19// newDecoderDict creates a new decoder dictionary. The whole dictionary
 20// will be used as reader buffer.
 21func newDecoderDict(dictCap int) (d *decoderDict, err error) {
 22	// lower limit supports easy test cases
 23	if !(1 <= dictCap && int64(dictCap) <= MaxDictCap) {
 24		return nil, errors.New("lzma: dictCap out of range")
 25	}
 26	d = &decoderDict{buf: *newBuffer(dictCap)}
 27	return d, nil
 28}
 29
 30// Reset clears the dictionary. The read buffer is not changed, so the
 31// buffered data can still be read.
 32func (d *decoderDict) Reset() {
 33	d.head = 0
 34}
 35
 36// WriteByte writes a single byte into the dictionary. It is used to
 37// write literals into the dictionary.
 38func (d *decoderDict) WriteByte(c byte) error {
 39	if err := d.buf.WriteByte(c); err != nil {
 40		return err
 41	}
 42	d.head++
 43	return nil
 44}
 45
 46// pos returns the position of the dictionary head.
 47func (d *decoderDict) pos() int64 { return d.head }
 48
 49// dictLen returns the actual length of the dictionary.
 50func (d *decoderDict) dictLen() int {
 51	capacity := d.buf.Cap()
 52	if d.head >= int64(capacity) {
 53		return capacity
 54	}
 55	return int(d.head)
 56}
 57
 58// byteAt returns a byte stored in the dictionary. If the distance is
 59// non-positive or exceeds the current length of the dictionary the zero
 60// byte is returned.
 61func (d *decoderDict) byteAt(dist int) byte {
 62	if !(0 < dist && dist <= d.dictLen()) {
 63		return 0
 64	}
 65	i := d.buf.front - dist
 66	if i < 0 {
 67		i += len(d.buf.data)
 68	}
 69	return d.buf.data[i]
 70}
 71
 72// writeMatch writes the match at the top of the dictionary. The given
 73// distance must point in the current dictionary and the length must not
 74// exceed the maximum length 273 supported in LZMA.
 75//
 76// The error value ErrNoSpace indicates that no space is available in
 77// the dictionary for writing. You need to read from the dictionary
 78// first.
 79func (d *decoderDict) writeMatch(dist int64, length int) error {
 80	if !(0 < dist && dist <= int64(d.dictLen())) {
 81		return errors.New("writeMatch: distance out of range")
 82	}
 83	if !(0 < length && length <= maxMatchLen) {
 84		return errors.New("writeMatch: length out of range")
 85	}
 86	if length > d.buf.Available() {
 87		return ErrNoSpace
 88	}
 89	d.head += int64(length)
 90
 91	i := d.buf.front - int(dist)
 92	if i < 0 {
 93		i += len(d.buf.data)
 94	}
 95	for length > 0 {
 96		var p []byte
 97		if i >= d.buf.front {
 98			p = d.buf.data[i:]
 99			i = 0
100		} else {
101			p = d.buf.data[i:d.buf.front]
102			i = d.buf.front
103		}
104		if len(p) > length {
105			p = p[:length]
106		}
107		if _, err := d.buf.Write(p); err != nil {
108			panic(fmt.Errorf("d.buf.Write returned error %s", err))
109		}
110		length -= len(p)
111	}
112	return nil
113}
114
115// Write writes the given bytes into the dictionary and advances the
116// head.
117func (d *decoderDict) Write(p []byte) (n int, err error) {
118	n, err = d.buf.Write(p)
119	d.head += int64(n)
120	return n, err
121}
122
123// Available returns the number of available bytes for writing into the
124// decoder dictionary.
125func (d *decoderDict) Available() int { return d.buf.Available() }
126
127// Read reads data from the buffer contained in the decoder dictionary.
128func (d *decoderDict) Read(p []byte) (n int, err error) { return d.buf.Read(p) }