Платформа ЦРНП "Мирокод" для разработки проектов
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.
171 lines
4.0 KiB
171 lines
4.0 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" |
|
) |
|
|
|
// buffer provides a circular buffer of bytes. If the front index equals |
|
// the rear index the buffer is empty. As a consequence front cannot be |
|
// equal rear for a full buffer. So a full buffer has a length that is |
|
// one byte less the the length of the data slice. |
|
type buffer struct { |
|
data []byte |
|
front int |
|
rear int |
|
} |
|
|
|
// newBuffer creates a buffer with the given size. |
|
func newBuffer(size int) *buffer { |
|
return &buffer{data: make([]byte, size+1)} |
|
} |
|
|
|
// Cap returns the capacity of the buffer. |
|
func (b *buffer) Cap() int { |
|
return len(b.data) - 1 |
|
} |
|
|
|
// Resets the buffer. The front and rear index are set to zero. |
|
func (b *buffer) Reset() { |
|
b.front = 0 |
|
b.rear = 0 |
|
} |
|
|
|
// Buffered returns the number of bytes buffered. |
|
func (b *buffer) Buffered() int { |
|
delta := b.front - b.rear |
|
if delta < 0 { |
|
delta += len(b.data) |
|
} |
|
return delta |
|
} |
|
|
|
// Available returns the number of bytes available for writing. |
|
func (b *buffer) Available() int { |
|
delta := b.rear - 1 - b.front |
|
if delta < 0 { |
|
delta += len(b.data) |
|
} |
|
return delta |
|
} |
|
|
|
// addIndex adds a non-negative integer to the index i and returns the |
|
// resulting index. The function takes care of wrapping the index as |
|
// well as potential overflow situations. |
|
func (b *buffer) addIndex(i int, n int) int { |
|
// subtraction of len(b.data) prevents overflow |
|
i += n - len(b.data) |
|
if i < 0 { |
|
i += len(b.data) |
|
} |
|
return i |
|
} |
|
|
|
// Read reads bytes from the buffer into p and returns the number of |
|
// bytes read. The function never returns an error but might return less |
|
// data than requested. |
|
func (b *buffer) Read(p []byte) (n int, err error) { |
|
n, err = b.Peek(p) |
|
b.rear = b.addIndex(b.rear, n) |
|
return n, err |
|
} |
|
|
|
// Peek reads bytes from the buffer into p without changing the buffer. |
|
// Peek will never return an error but might return less data than |
|
// requested. |
|
func (b *buffer) Peek(p []byte) (n int, err error) { |
|
m := b.Buffered() |
|
n = len(p) |
|
if m < n { |
|
n = m |
|
p = p[:n] |
|
} |
|
k := copy(p, b.data[b.rear:]) |
|
if k < n { |
|
copy(p[k:], b.data) |
|
} |
|
return n, nil |
|
} |
|
|
|
// Discard skips the n next bytes to read from the buffer, returning the |
|
// bytes discarded. |
|
// |
|
// If Discards skips fewer than n bytes, it returns an error. |
|
func (b *buffer) Discard(n int) (discarded int, err error) { |
|
if n < 0 { |
|
return 0, errors.New("buffer.Discard: negative argument") |
|
} |
|
m := b.Buffered() |
|
if m < n { |
|
n = m |
|
err = errors.New( |
|
"buffer.Discard: discarded less bytes then requested") |
|
} |
|
b.rear = b.addIndex(b.rear, n) |
|
return n, err |
|
} |
|
|
|
// ErrNoSpace indicates that there is insufficient space for the Write |
|
// operation. |
|
var ErrNoSpace = errors.New("insufficient space") |
|
|
|
// Write puts data into the buffer. If less bytes are written than |
|
// requested ErrNoSpace is returned. |
|
func (b *buffer) Write(p []byte) (n int, err error) { |
|
m := b.Available() |
|
n = len(p) |
|
if m < n { |
|
n = m |
|
p = p[:m] |
|
err = ErrNoSpace |
|
} |
|
k := copy(b.data[b.front:], p) |
|
if k < n { |
|
copy(b.data, p[k:]) |
|
} |
|
b.front = b.addIndex(b.front, n) |
|
return n, err |
|
} |
|
|
|
// WriteByte writes a single byte into the buffer. The error ErrNoSpace |
|
// is returned if no single byte is available in the buffer for writing. |
|
func (b *buffer) WriteByte(c byte) error { |
|
if b.Available() < 1 { |
|
return ErrNoSpace |
|
} |
|
b.data[b.front] = c |
|
b.front = b.addIndex(b.front, 1) |
|
return nil |
|
} |
|
|
|
// prefixLen returns the length of the common prefix of a and b. |
|
func prefixLen(a, b []byte) int { |
|
if len(a) > len(b) { |
|
a, b = b, a |
|
} |
|
for i, c := range a { |
|
if b[i] != c { |
|
return i |
|
} |
|
} |
|
return len(a) |
|
} |
|
|
|
// matchLen returns the length of the common prefix for the given |
|
// distance from the rear and the byte slice p. |
|
func (b *buffer) matchLen(distance int, p []byte) int { |
|
var n int |
|
i := b.rear - distance |
|
if i < 0 { |
|
if n = prefixLen(p, b.data[len(b.data)+i:]); n < -i { |
|
return n |
|
} |
|
p = p[n:] |
|
i = 0 |
|
} |
|
n += prefixLen(p, b.data[i:]) |
|
return n |
|
}
|
|
|