diff options
Diffstat (limited to 'vendor/github.com/ulikunitz/xz/lzma/writer.go')
-rw-r--r-- | vendor/github.com/ulikunitz/xz/lzma/writer.go | 209 |
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 | |||
5 | package lzma | ||
6 | |||
7 | import ( | ||
8 | "bufio" | ||
9 | "errors" | ||
10 | "io" | ||
11 | ) | ||
12 | |||
13 | // MinDictCap and MaxDictCap provide the range of supported dictionary | ||
14 | // capacities. | ||
15 | const ( | ||
16 | MinDictCap = 1 << 12 | ||
17 | MaxDictCap = 1<<32 - 1 | ||
18 | ) | ||
19 | |||
20 | // WriterConfig defines the configuration parameter for a writer. | ||
21 | type 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. | ||
46 | func (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. | ||
66 | func (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. | ||
99 | func (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. | ||
112 | type 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. | ||
121 | func (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. | ||
158 | func NewWriter(lzma io.Writer) (w *Writer, err error) { | ||
159 | return WriterConfig{}.NewWriter(lzma) | ||
160 | } | ||
161 | |||
162 | // writeHeader writes the LZMA header into the stream. | ||
163 | func (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. | ||
173 | func (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. | ||
194 | func (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 | } | ||