1// Copyright 2014-2019 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 5// Package lzma supports the decoding and encoding of LZMA streams. 6// Reader and Writer support the classic LZMA format. Reader2 and 7// Writer2 support the decoding and encoding of LZMA2 streams. 8// 9// The package is written completely in Go and doesn't rely on any external 10// library. 11package lzma 12 13import ( 14 "errors" 15 "io" 16) 17 18// ReaderConfig stores the parameters for the reader of the classic LZMA 19// format. 20type ReaderConfig struct { 21 DictCap int 22} 23 24// fill converts the zero values of the configuration to the default values. 25func (c *ReaderConfig) fill() { 26 if c.DictCap == 0 { 27 c.DictCap = 8 * 1024 * 1024 28 } 29} 30 31// Verify checks the reader configuration for errors. Zero values will 32// be replaced by default values. 33func (c *ReaderConfig) Verify() error { 34 c.fill() 35 if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) { 36 return errors.New("lzma: dictionary capacity is out of range") 37 } 38 return nil 39} 40 41// Reader provides a reader for LZMA files or streams. 42type Reader struct { 43 lzma io.Reader 44 h header 45 d *decoder 46} 47 48// NewReader creates a new reader for an LZMA stream using the classic 49// format. NewReader reads and checks the header of the LZMA stream. 50func NewReader(lzma io.Reader) (r *Reader, err error) { 51 return ReaderConfig{}.NewReader(lzma) 52} 53 54// NewReader creates a new reader for an LZMA stream in the classic 55// format. The function reads and verifies the the header of the LZMA 56// stream. 57func (c ReaderConfig) NewReader(lzma io.Reader) (r *Reader, err error) { 58 if err = c.Verify(); err != nil { 59 return nil, err 60 } 61 data := make([]byte, HeaderLen) 62 if _, err := io.ReadFull(lzma, data); err != nil { 63 if err == io.EOF { 64 return nil, errors.New("lzma: unexpected EOF") 65 } 66 return nil, err 67 } 68 r = &Reader{lzma: lzma} 69 if err = r.h.unmarshalBinary(data); err != nil { 70 return nil, err 71 } 72 if r.h.dictCap < MinDictCap { 73 return nil, errors.New("lzma: dictionary capacity too small") 74 } 75 dictCap := r.h.dictCap 76 if c.DictCap > dictCap { 77 dictCap = c.DictCap 78 } 79 80 state := newState(r.h.properties) 81 dict, err := newDecoderDict(dictCap) 82 if err != nil { 83 return nil, err 84 } 85 r.d, err = newDecoder(ByteReader(lzma), state, dict, r.h.size) 86 if err != nil { 87 return nil, err 88 } 89 return r, nil 90} 91 92// EOSMarker indicates that an EOS marker has been encountered. 93func (r *Reader) EOSMarker() bool { 94 return r.d.eosMarker 95} 96 97// Read returns uncompressed data. 98func (r *Reader) Read(p []byte) (n int, err error) { 99 return r.d.Read(p) 100} 101