1// Copyright 2014-2021 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) } 129