aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/ulikunitz/xz/lzma/writer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/writer.go')
-rw-r--r--vendor/github.com/ulikunitz/xz/lzma/writer.go209
1 files changed, 209 insertions, 0 deletions
diff --git a/vendor/github.com/ulikunitz/xz/lzma/writer.go b/vendor/github.com/ulikunitz/xz/lzma/writer.go
new file mode 100644
index 0000000..efe34fb
--- /dev/null
+++ b/vendor/github.com/ulikunitz/xz/lzma/writer.go
@@ -0,0 +1,209 @@
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.
4
5package lzma
6
7import (
8 "bufio"
9 "errors"
10 "io"
11)
12
13// MinDictCap and MaxDictCap provide the range of supported dictionary
14// capacities.
15const (
16 MinDictCap = 1 << 12
17 MaxDictCap = 1<<32 - 1
18)
19
20// WriterConfig defines the configuration parameter for a writer.
21type WriterConfig struct {
22 // Properties for the encoding. If the it is nil the value
23 // {LC: 3, LP: 0, PB: 2} will be chosen.
24 Properties *Properties
25 // The capacity of the dictionary. If DictCap is zero, the value
26 // 8 MiB will be chosen.
27 DictCap int
28 // Size of the lookahead buffer; value 0 indicates default size
29 // 4096
30 BufSize int
31 // Match algorithm
32 Matcher MatchAlgorithm
33 // SizeInHeader indicates that the header will contain an
34 // explicit size.
35 SizeInHeader bool
36 // Size of the data to be encoded. A positive value will imply
37 // than an explicit size will be set in the header.
38 Size int64
39 // EOSMarker requests whether the EOSMarker needs to be written.
40 // If no explicit size is been given the EOSMarker will be
41 // set automatically.
42 EOSMarker bool
43}
44
45// fill converts zero-value fields to their explicit default values.
46func (c *WriterConfig) fill() {
47 if c.Properties == nil {
48 c.Properties = &Properties{LC: 3, LP: 0, PB: 2}
49 }
50 if c.DictCap == 0 {
51 c.DictCap = 8 * 1024 * 1024
52 }
53 if c.BufSize == 0 {
54 c.BufSize = 4096
55 }
56 if c.Size > 0 {
57 c.SizeInHeader = true
58 }
59 if !c.SizeInHeader {
60 c.EOSMarker = true
61 }
62}
63
64// Verify checks WriterConfig for errors. Verify will replace zero
65// values with default values.
66func (c *WriterConfig) Verify() error {
67 c.fill()
68 var err error
69 if c == nil {
70 return errors.New("lzma: WriterConfig is nil")
71 }
72 if c.Properties == nil {
73 return errors.New("lzma: WriterConfig has no Properties set")
74 }
75 if err = c.Properties.verify(); err != nil {
76 return err
77 }
78 if !(MinDictCap <= c.DictCap && int64(c.DictCap) <= MaxDictCap) {
79 return errors.New("lzma: dictionary capacity is out of range")
80 }
81 if !(maxMatchLen <= c.BufSize) {
82 return errors.New("lzma: lookahead buffer size too small")
83 }
84 if c.SizeInHeader {
85 if c.Size < 0 {
86 return errors.New("lzma: negative size not supported")
87 }
88 } else if !c.EOSMarker {
89 return errors.New("lzma: EOS marker is required")
90 }
91 if err = c.Matcher.verify(); err != nil {
92 return err
93 }
94
95 return nil
96}
97
98// header returns the header structure for this configuration.
99func (c *WriterConfig) header() header {
100 h := header{
101 properties: *c.Properties,
102 dictCap: c.DictCap,
103 size: -1,
104 }
105 if c.SizeInHeader {
106 h.size = c.Size
107 }
108 return h
109}
110
111// Writer writes an LZMA stream in the classic format.
112type Writer struct {
113 h header
114 bw io.ByteWriter
115 buf *bufio.Writer
116 e *encoder
117}
118
119// NewWriter creates a new LZMA writer for the classic format. The
120// method will write the header to the underlying stream.
121func (c WriterConfig) NewWriter(lzma io.Writer) (w *Writer, err error) {
122 if err = c.Verify(); err != nil {
123 return nil, err
124 }
125 w = &Writer{h: c.header()}
126
127 var ok bool
128 w.bw, ok = lzma.(io.ByteWriter)
129 if !ok {
130 w.buf = bufio.NewWriter(lzma)
131 w.bw = w.buf
132 }
133 state := newState(w.h.properties)
134 m, err := c.Matcher.new(w.h.dictCap)
135 if err != nil {
136 return nil, err
137 }
138 dict, err := newEncoderDict(w.h.dictCap, c.BufSize, m)
139 if err != nil {
140 return nil, err
141 }
142 var flags encoderFlags
143 if c.EOSMarker {
144 flags = eosMarker
145 }
146 if w.e, err = newEncoder(w.bw, state, dict, flags); err != nil {
147 return nil, err
148 }
149
150 if err = w.writeHeader(); err != nil {
151 return nil, err
152 }
153 return w, nil
154}
155
156// NewWriter creates a new LZMA writer using the classic format. The
157// function writes the header to the underlying stream.
158func NewWriter(lzma io.Writer) (w *Writer, err error) {
159 return WriterConfig{}.NewWriter(lzma)
160}
161
162// writeHeader writes the LZMA header into the stream.
163func (w *Writer) writeHeader() error {
164 data, err := w.h.marshalBinary()
165 if err != nil {
166 return err
167 }
168 _, err = w.bw.(io.Writer).Write(data)
169 return err
170}
171
172// Write puts data into the Writer.
173func (w *Writer) Write(p []byte) (n int, err error) {
174 if w.h.size >= 0 {
175 m := w.h.size
176 m -= w.e.Compressed() + int64(w.e.dict.Buffered())
177 if m < 0 {
178 m = 0
179 }
180 if m < int64(len(p)) {
181 p = p[:m]
182 err = ErrNoSpace
183 }
184 }
185 var werr error
186 if n, werr = w.e.Write(p); werr != nil {
187 err = werr
188 }
189 return n, err
190}
191
192// Close closes the writer stream. It ensures that all data from the
193// buffer will be compressed and the LZMA stream will be finished.
194func (w *Writer) Close() error {
195 if w.h.size >= 0 {
196 n := w.e.Compressed() + int64(w.e.dict.Buffered())
197 if n != w.h.size {
198 return errSize
199 }
200 }
201 err := w.e.Close()
202 if w.buf != nil {
203 ferr := w.buf.Flush()
204 if err == nil {
205 err = ferr
206 }
207 }
208 return err
209}