Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.4 KiB
128 lines
3.4 KiB
// Copyright 2014-2021 Ulrich Kunitz. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package lzma |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
) |
|
|
|
// decoderDict provides the dictionary for the decoder. The whole |
|
// dictionary is used as reader buffer. |
|
type decoderDict struct { |
|
buf buffer |
|
head int64 |
|
} |
|
|
|
// newDecoderDict creates a new decoder dictionary. The whole dictionary |
|
// will be used as reader buffer. |
|
func newDecoderDict(dictCap int) (d *decoderDict, err error) { |
|
// lower limit supports easy test cases |
|
if !(1 <= dictCap && int64(dictCap) <= MaxDictCap) { |
|
return nil, errors.New("lzma: dictCap out of range") |
|
} |
|
d = &decoderDict{buf: *newBuffer(dictCap)} |
|
return d, nil |
|
} |
|
|
|
// Reset clears the dictionary. The read buffer is not changed, so the |
|
// buffered data can still be read. |
|
func (d *decoderDict) Reset() { |
|
d.head = 0 |
|
} |
|
|
|
// WriteByte writes a single byte into the dictionary. It is used to |
|
// write literals into the dictionary. |
|
func (d *decoderDict) WriteByte(c byte) error { |
|
if err := d.buf.WriteByte(c); err != nil { |
|
return err |
|
} |
|
d.head++ |
|
return nil |
|
} |
|
|
|
// pos returns the position of the dictionary head. |
|
func (d *decoderDict) pos() int64 { return d.head } |
|
|
|
// dictLen returns the actual length of the dictionary. |
|
func (d *decoderDict) dictLen() int { |
|
capacity := d.buf.Cap() |
|
if d.head >= int64(capacity) { |
|
return capacity |
|
} |
|
return int(d.head) |
|
} |
|
|
|
// byteAt returns a byte stored in the dictionary. If the distance is |
|
// non-positive or exceeds the current length of the dictionary the zero |
|
// byte is returned. |
|
func (d *decoderDict) byteAt(dist int) byte { |
|
if !(0 < dist && dist <= d.dictLen()) { |
|
return 0 |
|
} |
|
i := d.buf.front - dist |
|
if i < 0 { |
|
i += len(d.buf.data) |
|
} |
|
return d.buf.data[i] |
|
} |
|
|
|
// writeMatch writes the match at the top of the dictionary. The given |
|
// distance must point in the current dictionary and the length must not |
|
// exceed the maximum length 273 supported in LZMA. |
|
// |
|
// The error value ErrNoSpace indicates that no space is available in |
|
// the dictionary for writing. You need to read from the dictionary |
|
// first. |
|
func (d *decoderDict) writeMatch(dist int64, length int) error { |
|
if !(0 < dist && dist <= int64(d.dictLen())) { |
|
return errors.New("writeMatch: distance out of range") |
|
} |
|
if !(0 < length && length <= maxMatchLen) { |
|
return errors.New("writeMatch: length out of range") |
|
} |
|
if length > d.buf.Available() { |
|
return ErrNoSpace |
|
} |
|
d.head += int64(length) |
|
|
|
i := d.buf.front - int(dist) |
|
if i < 0 { |
|
i += len(d.buf.data) |
|
} |
|
for length > 0 { |
|
var p []byte |
|
if i >= d.buf.front { |
|
p = d.buf.data[i:] |
|
i = 0 |
|
} else { |
|
p = d.buf.data[i:d.buf.front] |
|
i = d.buf.front |
|
} |
|
if len(p) > length { |
|
p = p[:length] |
|
} |
|
if _, err := d.buf.Write(p); err != nil { |
|
panic(fmt.Errorf("d.buf.Write returned error %s", err)) |
|
} |
|
length -= len(p) |
|
} |
|
return nil |
|
} |
|
|
|
// Write writes the given bytes into the dictionary and advances the |
|
// head. |
|
func (d *decoderDict) Write(p []byte) (n int, err error) { |
|
n, err = d.buf.Write(p) |
|
d.head += int64(n) |
|
return n, err |
|
} |
|
|
|
// Available returns the number of available bytes for writing into the |
|
// decoder dictionary. |
|
func (d *decoderDict) Available() int { return d.buf.Available() } |
|
|
|
// Read reads data from the buffer contained in the decoder dictionary. |
|
func (d *decoderDict) Read(p []byte) (n int, err error) { return d.buf.Read(p) }
|
|
|