1 // Copyright 2014-2017 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.
12 // opLenMargin provides the upper limit of the number of bytes required
13 // to encode a single operation.
14 const opLenMargin = 16
16 // compressFlags control the compression process.
17 type compressFlags uint32
19 // Values for compressFlags.
21 // all data should be compressed, even if compression is not
23 all compressFlags = 1 << iota
26 // encoderFlags provide the flags for an encoder.
27 type encoderFlags uint32
29 // Flags for the encoder.
31 // eosMarker requests an EOS marker to be written.
32 eosMarker encoderFlags = 1 << iota
35 // Encoder compresses data buffered in the encoder dictionary and writes
36 // it into a byte writer.
42 // generate eos marker
48 // newEncoder creates a new encoder. If the byte writer must be
49 // limited use LimitedByteWriter provided by this package. The flags
50 // argument supports the eosMarker flag, controlling whether a
51 // terminating end-of-stream marker must be written.
52 func newEncoder(bw io.ByteWriter, state *state, dict *encoderDict,
53 flags encoderFlags) (e *encoder, err error) {
55 re, err := newRangeEncoder(bw)
63 marker: flags&eosMarker != 0,
73 // Write writes the bytes from p into the dictionary. If not enough
74 // space is available the data in the dictionary buffer will be
75 // compressed to make additional space available. If the limit of the
76 // underlying writer has been reached ErrLimit will be returned.
77 func (e *encoder) Write(p []byte) (n int, err error) {
79 k, err := e.dict.Write(p[n:])
81 if err == ErrNoSpace {
82 if err = e.compress(0); err != nil {
91 // Reopen reopens the encoder with a new byte writer.
92 func (e *encoder) Reopen(bw io.ByteWriter) error {
94 if e.re, err = newRangeEncoder(bw); err != nil {
97 e.start = e.dict.Pos()
102 // writeLiteral writes a literal into the LZMA stream
103 func (e *encoder) writeLiteral(l lit) error {
105 state, state2, _ := e.state.states(e.dict.Pos())
106 if err = e.state.isMatch[state2].Encode(e.re, 0); err != nil {
109 litState := e.state.litState(e.dict.ByteAt(1), e.dict.Pos())
110 match := e.dict.ByteAt(int(e.state.rep[0]) + 1)
111 err = e.state.litCodec.Encode(e.re, l.b, state, match, litState)
115 e.state.updateStateLiteral()
119 // iverson implements the Iverson operator as proposed by Donald Knuth in his
120 // book Concrete Mathematics.
121 func iverson(ok bool) uint32 {
128 // writeMatch writes a repetition operation into the operation stream
129 func (e *encoder) writeMatch(m match) error {
131 if !(minDistance <= m.distance && m.distance <= maxDistance) {
132 panic(fmt.Errorf("match distance %d out of range", m.distance))
134 dist := uint32(m.distance - minDistance)
135 if !(minMatchLen <= m.n && m.n <= maxMatchLen) &&
136 !(dist == e.state.rep[0] && m.n == 1) {
138 "match length %d out of range; dist %d rep[0] %d",
139 m.n, dist, e.state.rep[0]))
141 state, state2, posState := e.state.states(e.dict.Pos())
142 if err = e.state.isMatch[state2].Encode(e.re, 1); err != nil {
147 if e.state.rep[g] == dist {
152 if err = e.state.isRep[state].Encode(e.re, b); err != nil {
155 n := uint32(m.n - minMatchLen)
158 e.state.rep[3], e.state.rep[2], e.state.rep[1], e.state.rep[0] =
159 e.state.rep[2], e.state.rep[1], e.state.rep[0], dist
160 e.state.updateStateMatch()
161 if err = e.state.lenCodec.Encode(e.re, n, posState); err != nil {
164 return e.state.distCodec.Encode(e.re, dist, n)
167 if err = e.state.isRepG0[state].Encode(e.re, b); err != nil {
172 b = iverson(m.n != 1)
173 if err = e.state.isRepG0Long[state2].Encode(e.re, b); err != nil {
177 e.state.updateStateShortRep()
183 if err = e.state.isRepG1[state].Encode(e.re, b); err != nil {
189 err = e.state.isRepG2[state].Encode(e.re, b)
194 e.state.rep[3] = e.state.rep[2]
196 e.state.rep[2] = e.state.rep[1]
198 e.state.rep[1] = e.state.rep[0]
199 e.state.rep[0] = dist
201 e.state.updateStateRep()
202 return e.state.repLenCodec.Encode(e.re, n, posState)
205 // writeOp writes a single operation to the range encoder. The function
206 // checks whether there is enough space available to close the LZMA
208 func (e *encoder) writeOp(op operation) error {
209 if e.re.Available() < int64(e.margin) {
212 switch x := op.(type) {
214 return e.writeLiteral(x)
216 return e.writeMatch(x)
218 panic("unexpected operation")
222 // compress compressed data from the dictionary buffer. If the flag all
223 // is set, all data in the dictionary buffer will be compressed. The
224 // function returns ErrLimit if the underlying writer has reached its
226 func (e *encoder) compress(flags compressFlags) error {
233 for d.Buffered() > n {
234 op := m.NextOp(e.state.rep)
235 if err := e.writeOp(op); err != nil {
243 // eosMatch is a pseudo operation that indicates the end of the stream.
244 var eosMatch = match{distance: maxDistance, n: minMatchLen}
246 // Close terminates the LZMA stream. If requested the end-of-stream
247 // marker will be written. If the byte writer limit has been or will be
248 // reached during compression of the remaining data in the buffer the
249 // LZMA stream will be closed and data will remain in the buffer.
250 func (e *encoder) Close() error {
251 err := e.compress(all)
252 if err != nil && err != ErrLimit {
256 if err := e.writeMatch(eosMatch); err != nil {
264 // Compressed returns the number bytes of the input data that been
266 func (e *encoder) Compressed() int64 {
267 return e.dict.Pos() - e.start