main
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)
10
11// buffer provides a circular buffer of bytes. If the front index equals
12// the rear index the buffer is empty. As a consequence front cannot be
13// equal rear for a full buffer. So a full buffer has a length that is
14// one byte less the the length of the data slice.
15type buffer struct {
16 data []byte
17 front int
18 rear int
19}
20
21// newBuffer creates a buffer with the given size.
22func newBuffer(size int) *buffer {
23 return &buffer{data: make([]byte, size+1)}
24}
25
26// Cap returns the capacity of the buffer.
27func (b *buffer) Cap() int {
28 return len(b.data) - 1
29}
30
31// Resets the buffer. The front and rear index are set to zero.
32func (b *buffer) Reset() {
33 b.front = 0
34 b.rear = 0
35}
36
37// Buffered returns the number of bytes buffered.
38func (b *buffer) Buffered() int {
39 delta := b.front - b.rear
40 if delta < 0 {
41 delta += len(b.data)
42 }
43 return delta
44}
45
46// Available returns the number of bytes available for writing.
47func (b *buffer) Available() int {
48 delta := b.rear - 1 - b.front
49 if delta < 0 {
50 delta += len(b.data)
51 }
52 return delta
53}
54
55// addIndex adds a non-negative integer to the index i and returns the
56// resulting index. The function takes care of wrapping the index as
57// well as potential overflow situations.
58func (b *buffer) addIndex(i int, n int) int {
59 // subtraction of len(b.data) prevents overflow
60 i += n - len(b.data)
61 if i < 0 {
62 i += len(b.data)
63 }
64 return i
65}
66
67// Read reads bytes from the buffer into p and returns the number of
68// bytes read. The function never returns an error but might return less
69// data than requested.
70func (b *buffer) Read(p []byte) (n int, err error) {
71 n, err = b.Peek(p)
72 b.rear = b.addIndex(b.rear, n)
73 return n, err
74}
75
76// Peek reads bytes from the buffer into p without changing the buffer.
77// Peek will never return an error but might return less data than
78// requested.
79func (b *buffer) Peek(p []byte) (n int, err error) {
80 m := b.Buffered()
81 n = len(p)
82 if m < n {
83 n = m
84 p = p[:n]
85 }
86 k := copy(p, b.data[b.rear:])
87 if k < n {
88 copy(p[k:], b.data)
89 }
90 return n, nil
91}
92
93// Discard skips the n next bytes to read from the buffer, returning the
94// bytes discarded.
95//
96// If Discards skips fewer than n bytes, it returns an error.
97func (b *buffer) Discard(n int) (discarded int, err error) {
98 if n < 0 {
99 return 0, errors.New("buffer.Discard: negative argument")
100 }
101 m := b.Buffered()
102 if m < n {
103 n = m
104 err = errors.New(
105 "buffer.Discard: discarded less bytes then requested")
106 }
107 b.rear = b.addIndex(b.rear, n)
108 return n, err
109}
110
111// ErrNoSpace indicates that there is insufficient space for the Write
112// operation.
113var ErrNoSpace = errors.New("insufficient space")
114
115// Write puts data into the buffer. If less bytes are written than
116// requested ErrNoSpace is returned.
117func (b *buffer) Write(p []byte) (n int, err error) {
118 m := b.Available()
119 n = len(p)
120 if m < n {
121 n = m
122 p = p[:m]
123 err = ErrNoSpace
124 }
125 k := copy(b.data[b.front:], p)
126 if k < n {
127 copy(b.data, p[k:])
128 }
129 b.front = b.addIndex(b.front, n)
130 return n, err
131}
132
133// WriteByte writes a single byte into the buffer. The error ErrNoSpace
134// is returned if no single byte is available in the buffer for writing.
135func (b *buffer) WriteByte(c byte) error {
136 if b.Available() < 1 {
137 return ErrNoSpace
138 }
139 b.data[b.front] = c
140 b.front = b.addIndex(b.front, 1)
141 return nil
142}
143
144// prefixLen returns the length of the common prefix of a and b.
145func prefixLen(a, b []byte) int {
146 if len(a) > len(b) {
147 a, b = b, a
148 }
149 for i, c := range a {
150 if b[i] != c {
151 return i
152 }
153 }
154 return len(a)
155}
156
157// matchLen returns the length of the common prefix for the given
158// distance from the rear and the byte slice p.
159func (b *buffer) matchLen(distance int, p []byte) int {
160 var n int
161 i := b.rear - distance
162 if i < 0 {
163 if n = prefixLen(p, b.data[len(b.data)+i:]); n < -i {
164 return n
165 }
166 p = p[n:]
167 i = 0
168 }
169 n += prefixLen(p, b.data[i:])
170 return n
171}