1228753Smm/*-
2231200Smm * Copyright (c) 2003-2010 Tim Kientzle
3232153Smm * Copyright (c) 2009-2012 Michihiro NAKAJIMA
4228753Smm * All rights reserved.
5228753Smm *
6228753Smm * Redistribution and use in source and binary forms, with or without
7228753Smm * modification, are permitted provided that the following conditions
8228753Smm * are met:
9228753Smm * 1. Redistributions of source code must retain the above copyright
10228753Smm *    notice, this list of conditions and the following disclaimer.
11228753Smm * 2. Redistributions in binary form must reproduce the above copyright
12228753Smm *    notice, this list of conditions and the following disclaimer in the
13228753Smm *    documentation and/or other materials provided with the distribution.
14228753Smm *
15228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25228753Smm */
26228753Smm
27228753Smm#include "archive_platform.h"
28228753Smm
29228753Smm__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 201108 2009-12-28 03:28:21Z kientzle $");
30228753Smm
31228753Smm#ifdef HAVE_ERRNO_H
32228753Smm#include <errno.h>
33228753Smm#endif
34228753Smm#ifdef HAVE_STDLIB_H
35228753Smm#include <stdlib.h>
36228753Smm#endif
37228753Smm#ifdef HAVE_STRING_H
38228753Smm#include <string.h>
39228753Smm#endif
40228753Smm#include <time.h>
41228753Smm#ifdef HAVE_LZMA_H
42228753Smm#include <lzma.h>
43228753Smm#endif
44228753Smm
45228753Smm#include "archive.h"
46231200Smm#include "archive_endian.h"
47228753Smm#include "archive_private.h"
48228753Smm#include "archive_write_private.h"
49228753Smm
50231200Smm#if ARCHIVE_VERSION_NUMBER < 4000000
51228753Smmint
52231200Smmarchive_write_set_compression_lzip(struct archive *a)
53231200Smm{
54231200Smm	__archive_write_filters_free(a);
55231200Smm	return (archive_write_add_filter_lzip(a));
56231200Smm}
57231200Smm
58231200Smmint
59231200Smmarchive_write_set_compression_lzma(struct archive *a)
60231200Smm{
61231200Smm	__archive_write_filters_free(a);
62231200Smm	return (archive_write_add_filter_lzma(a));
63231200Smm}
64231200Smm
65231200Smmint
66228753Smmarchive_write_set_compression_xz(struct archive *a)
67228753Smm{
68231200Smm	__archive_write_filters_free(a);
69231200Smm	return (archive_write_add_filter_xz(a));
70231200Smm}
71231200Smm
72231200Smm#endif
73231200Smm
74231200Smm#ifndef HAVE_LZMA_H
75231200Smmint
76231200Smmarchive_write_add_filter_xz(struct archive *a)
77231200Smm{
78228753Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
79228753Smm	    "xz compression not supported on this platform");
80228753Smm	return (ARCHIVE_FATAL);
81228753Smm}
82228753Smm
83228753Smmint
84231200Smmarchive_write_add_filter_lzma(struct archive *a)
85228753Smm{
86228753Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
87228753Smm	    "lzma compression not supported on this platform");
88228753Smm	return (ARCHIVE_FATAL);
89228753Smm}
90231200Smm
91231200Smmint
92231200Smmarchive_write_add_filter_lzip(struct archive *a)
93231200Smm{
94231200Smm	archive_set_error(a, ARCHIVE_ERRNO_MISC,
95231200Smm	    "lzma compression not supported on this platform");
96231200Smm	return (ARCHIVE_FATAL);
97231200Smm}
98228753Smm#else
99228753Smm/* Don't compile this if we don't have liblzma. */
100228753Smm
101228753Smmstruct private_data {
102231200Smm	int		 compression_level;
103302001Smm	uint32_t	 threads;
104228753Smm	lzma_stream	 stream;
105228753Smm	lzma_filter	 lzmafilters[2];
106228753Smm	lzma_options_lzma lzma_opt;
107228753Smm	int64_t		 total_in;
108228753Smm	unsigned char	*compressed;
109228753Smm	size_t		 compressed_buffer_size;
110231200Smm	int64_t		 total_out;
111231200Smm	/* the CRC32 value of uncompressed data for lzip */
112231200Smm	uint32_t	 crc32;
113228753Smm};
114228753Smm
115231200Smmstatic int	archive_compressor_xz_options(struct archive_write_filter *,
116228753Smm		    const char *, const char *);
117231200Smmstatic int	archive_compressor_xz_open(struct archive_write_filter *);
118231200Smmstatic int	archive_compressor_xz_write(struct archive_write_filter *,
119228753Smm		    const void *, size_t);
120231200Smmstatic int	archive_compressor_xz_close(struct archive_write_filter *);
121231200Smmstatic int	archive_compressor_xz_free(struct archive_write_filter *);
122231200Smmstatic int	drive_compressor(struct archive_write_filter *,
123231200Smm		    struct private_data *, int finishing);
124228753Smm
125231200Smmstruct option_value {
126231200Smm	uint32_t dict_size;
127231200Smm	uint32_t nice_len;
128231200Smm	lzma_match_finder mf;
129231200Smm};
130231200Smmstatic const struct option_value option_values[] = {
131231200Smm	{ 1 << 16, 32, LZMA_MF_HC3},
132231200Smm	{ 1 << 20, 32, LZMA_MF_HC3},
133231200Smm	{ 3 << 19, 32, LZMA_MF_HC4},
134231200Smm	{ 1 << 21, 32, LZMA_MF_BT4},
135231200Smm	{ 3 << 20, 32, LZMA_MF_BT4},
136231200Smm	{ 1 << 22, 32, LZMA_MF_BT4},
137231200Smm	{ 1 << 23, 64, LZMA_MF_BT4},
138231200Smm	{ 1 << 24, 64, LZMA_MF_BT4},
139231200Smm	{ 3 << 23, 64, LZMA_MF_BT4},
140231200Smm	{ 1 << 25, 64, LZMA_MF_BT4}
141231200Smm};
142228753Smm
143231200Smmstatic int
144231200Smmcommon_setup(struct archive_write_filter *f)
145228753Smm{
146231200Smm	struct private_data *data;
147231200Smm	struct archive_write *a = (struct archive_write *)f->archive;
148231200Smm	data = calloc(1, sizeof(*data));
149231200Smm	if (data == NULL) {
150228753Smm		archive_set_error(&a->archive, ENOMEM, "Out of memory");
151228753Smm		return (ARCHIVE_FATAL);
152228753Smm	}
153231200Smm	f->data = data;
154231200Smm	data->compression_level = LZMA_PRESET_DEFAULT;
155302001Smm	data->threads = 1;
156231200Smm	f->open = &archive_compressor_xz_open;
157231200Smm	f->close = archive_compressor_xz_close;
158231200Smm	f->free = archive_compressor_xz_free;
159231200Smm	f->options = &archive_compressor_xz_options;
160228753Smm	return (ARCHIVE_OK);
161228753Smm}
162228753Smm
163231200Smm/*
164231200Smm * Add an xz compression filter to this write handle.
165231200Smm */
166231200Smmint
167231200Smmarchive_write_add_filter_xz(struct archive *_a)
168231200Smm{
169231200Smm	struct archive_write_filter *f;
170231200Smm	int r;
171231200Smm
172231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
173231200Smm	    ARCHIVE_STATE_NEW, "archive_write_add_filter_xz");
174231200Smm	f = __archive_write_allocate_filter(_a);
175231200Smm	r = common_setup(f);
176231200Smm	if (r == ARCHIVE_OK) {
177248616Smm		f->code = ARCHIVE_FILTER_XZ;
178231200Smm		f->name = "xz";
179231200Smm	}
180231200Smm	return (r);
181231200Smm}
182231200Smm
183228753Smm/* LZMA is handled identically, we just need a different compression
184228753Smm * code set.  (The liblzma setup looks at the code to determine
185228753Smm * the one place that XZ and LZMA require different handling.) */
186228753Smmint
187231200Smmarchive_write_add_filter_lzma(struct archive *_a)
188228753Smm{
189231200Smm	struct archive_write_filter *f;
190231200Smm	int r;
191231200Smm
192231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
193231200Smm	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzma");
194231200Smm	f = __archive_write_allocate_filter(_a);
195231200Smm	r = common_setup(f);
196231200Smm	if (r == ARCHIVE_OK) {
197248616Smm		f->code = ARCHIVE_FILTER_LZMA;
198231200Smm		f->name = "lzma";
199231200Smm	}
200231200Smm	return (r);
201228753Smm}
202228753Smm
203231200Smmint
204231200Smmarchive_write_add_filter_lzip(struct archive *_a)
205231200Smm{
206231200Smm	struct archive_write_filter *f;
207231200Smm	int r;
208231200Smm
209231200Smm	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
210231200Smm	    ARCHIVE_STATE_NEW, "archive_write_add_filter_lzip");
211231200Smm	f = __archive_write_allocate_filter(_a);
212231200Smm	r = common_setup(f);
213231200Smm	if (r == ARCHIVE_OK) {
214248616Smm		f->code = ARCHIVE_FILTER_LZIP;
215231200Smm		f->name = "lzip";
216231200Smm	}
217231200Smm	return (r);
218231200Smm}
219231200Smm
220228753Smmstatic int
221231200Smmarchive_compressor_xz_init_stream(struct archive_write_filter *f,
222231200Smm    struct private_data *data)
223228753Smm{
224228753Smm	static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
225228753Smm	int ret;
226302001Smm#ifdef HAVE_LZMA_STREAM_ENCODER_MT
227302001Smm	lzma_mt mt_options;
228302001Smm#endif
229228753Smm
230231200Smm	data->stream = lzma_stream_init_data;
231231200Smm	data->stream.next_out = data->compressed;
232231200Smm	data->stream.avail_out = data->compressed_buffer_size;
233302001Smm	if (f->code == ARCHIVE_FILTER_XZ) {
234302001Smm#ifdef HAVE_LZMA_STREAM_ENCODER_MT
235302001Smm		if (data->threads != 1) {
236313571Smm			memset(&mt_options, 0, sizeof(mt_options));
237302001Smm			mt_options.threads = data->threads;
238302001Smm			mt_options.timeout = 300;
239302001Smm			mt_options.filters = data->lzmafilters;
240302001Smm			mt_options.check = LZMA_CHECK_CRC64;
241302001Smm			ret = lzma_stream_encoder_mt(&(data->stream),
242302001Smm			    &mt_options);
243302001Smm		} else
244302001Smm#endif
245302001Smm			ret = lzma_stream_encoder(&(data->stream),
246302001Smm			    data->lzmafilters, LZMA_CHECK_CRC64);
247302001Smm	} else if (f->code == ARCHIVE_FILTER_LZMA) {
248231200Smm		ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
249302001Smm	} else {	/* ARCHIVE_FILTER_LZIP */
250231200Smm		int dict_size = data->lzma_opt.dict_size;
251231200Smm		int ds, log2dic, wedges;
252231200Smm
253231200Smm		/* Calculate a coded dictionary size */
254231200Smm		if (dict_size < (1 << 12) || dict_size > (1 << 27)) {
255231200Smm			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
256302001Smm			    "Unacceptable dictionary size for lzip: %d",
257231200Smm			    dict_size);
258231200Smm			return (ARCHIVE_FATAL);
259231200Smm		}
260231200Smm		for (log2dic = 27; log2dic >= 12; log2dic--) {
261231200Smm			if (dict_size & (1 << log2dic))
262231200Smm				break;
263231200Smm		}
264231200Smm		if (dict_size > (1 << log2dic)) {
265231200Smm			log2dic++;
266231200Smm			wedges =
267231200Smm			    ((1 << log2dic) - dict_size) / (1 << (log2dic - 4));
268231200Smm		} else
269231200Smm			wedges = 0;
270231200Smm		ds = ((wedges << 5) & 0xe0) | (log2dic & 0x1f);
271231200Smm
272231200Smm		data->crc32 = 0;
273231200Smm		/* Make a header */
274231200Smm		data->compressed[0] = 0x4C;
275231200Smm		data->compressed[1] = 0x5A;
276231200Smm		data->compressed[2] = 0x49;
277231200Smm		data->compressed[3] = 0x50;
278231200Smm		data->compressed[4] = 1;/* Version */
279231200Smm		data->compressed[5] = (unsigned char)ds;
280231200Smm		data->stream.next_out += 6;
281231200Smm		data->stream.avail_out -= 6;
282231200Smm
283231200Smm		ret = lzma_raw_encoder(&(data->stream), data->lzmafilters);
284231200Smm	}
285228753Smm	if (ret == LZMA_OK)
286228753Smm		return (ARCHIVE_OK);
287228753Smm
288228753Smm	switch (ret) {
289228753Smm	case LZMA_MEM_ERROR:
290231200Smm		archive_set_error(f->archive, ENOMEM,
291228753Smm		    "Internal error initializing compression library: "
292228753Smm		    "Cannot allocate memory");
293228753Smm		break;
294228753Smm	default:
295231200Smm		archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
296228753Smm		    "Internal error initializing compression library: "
297228753Smm		    "It's a bug in liblzma");
298228753Smm		break;
299228753Smm	}
300228753Smm	return (ARCHIVE_FATAL);
301228753Smm}
302228753Smm
303228753Smm/*
304228753Smm * Setup callback.
305228753Smm */
306228753Smmstatic int
307231200Smmarchive_compressor_xz_open(struct archive_write_filter *f)
308228753Smm{
309231200Smm	struct private_data *data = f->data;
310228753Smm	int ret;
311228753Smm
312231200Smm	if (data->compressed == NULL) {
313238856Smm		size_t bs = 65536, bpb;
314238856Smm		if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
315238856Smm			/* Buffer size should be a multiple number of the of bytes
316238856Smm			 * per block for performance. */
317238856Smm			bpb = archive_write_get_bytes_per_block(f->archive);
318238856Smm			if (bpb > bs)
319238856Smm				bs = bpb;
320238856Smm			else if (bpb != 0)
321238856Smm				bs -= bs % bpb;
322238856Smm		}
323238856Smm		data->compressed_buffer_size = bs;
324231200Smm		data->compressed
325231200Smm		    = (unsigned char *)malloc(data->compressed_buffer_size);
326231200Smm		if (data->compressed == NULL) {
327231200Smm			archive_set_error(f->archive, ENOMEM,
328231200Smm			    "Can't allocate data for compression buffer");
329231200Smm			return (ARCHIVE_FATAL);
330231200Smm		}
331228753Smm	}
332228753Smm
333231200Smm	f->write = archive_compressor_xz_write;
334228753Smm
335228753Smm	/* Initialize compression library. */
336248616Smm	if (f->code == ARCHIVE_FILTER_LZIP) {
337231200Smm		const struct option_value *val =
338231200Smm		    &option_values[data->compression_level];
339231200Smm
340231200Smm		data->lzma_opt.dict_size = val->dict_size;
341231200Smm		data->lzma_opt.preset_dict = NULL;
342231200Smm		data->lzma_opt.preset_dict_size = 0;
343231200Smm		data->lzma_opt.lc = LZMA_LC_DEFAULT;
344231200Smm		data->lzma_opt.lp = LZMA_LP_DEFAULT;
345231200Smm		data->lzma_opt.pb = LZMA_PB_DEFAULT;
346231200Smm		data->lzma_opt.mode =
347231200Smm		    data->compression_level<= 2? LZMA_MODE_FAST:LZMA_MODE_NORMAL;
348231200Smm		data->lzma_opt.nice_len = val->nice_len;
349231200Smm		data->lzma_opt.mf = val->mf;
350231200Smm		data->lzma_opt.depth = 0;
351231200Smm		data->lzmafilters[0].id = LZMA_FILTER_LZMA1;
352231200Smm		data->lzmafilters[0].options = &data->lzma_opt;
353231200Smm		data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
354231200Smm	} else {
355231200Smm		if (lzma_lzma_preset(&data->lzma_opt, data->compression_level)) {
356231200Smm			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
357231200Smm			    "Internal error initializing compression library");
358231200Smm		}
359231200Smm		data->lzmafilters[0].id = LZMA_FILTER_LZMA2;
360231200Smm		data->lzmafilters[0].options = &data->lzma_opt;
361231200Smm		data->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
362228753Smm	}
363231200Smm	ret = archive_compressor_xz_init_stream(f, data);
364228753Smm	if (ret == LZMA_OK) {
365231200Smm		f->data = data;
366228753Smm		return (0);
367228753Smm	}
368228753Smm	return (ARCHIVE_FATAL);
369228753Smm}
370228753Smm
371228753Smm/*
372228753Smm * Set write options.
373228753Smm */
374228753Smmstatic int
375231200Smmarchive_compressor_xz_options(struct archive_write_filter *f,
376231200Smm    const char *key, const char *value)
377228753Smm{
378231200Smm	struct private_data *data = (struct private_data *)f->data;
379228753Smm
380228753Smm	if (strcmp(key, "compression-level") == 0) {
381228753Smm		if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
382228753Smm		    value[1] != '\0')
383228753Smm			return (ARCHIVE_WARN);
384231200Smm		data->compression_level = value[0] - '0';
385368708Smm		if (data->compression_level > 9)
386368708Smm			data->compression_level = 9;
387228753Smm		return (ARCHIVE_OK);
388302001Smm	} else if (strcmp(key, "threads") == 0) {
389348608Smm		char *endptr;
390348608Smm
391302001Smm		if (value == NULL)
392302001Smm			return (ARCHIVE_WARN);
393348608Smm		errno = 0;
394348608Smm		data->threads = (int)strtoul(value, &endptr, 10);
395348608Smm		if (errno != 0 || *endptr != '\0') {
396302001Smm			data->threads = 1;
397302001Smm			return (ARCHIVE_WARN);
398302001Smm		}
399302001Smm		if (data->threads == 0) {
400302001Smm#ifdef HAVE_LZMA_STREAM_ENCODER_MT
401302001Smm			data->threads = lzma_cputhreads();
402302001Smm#else
403302001Smm			data->threads = 1;
404302001Smm#endif
405302001Smm		}
406302001Smm		return (ARCHIVE_OK);
407228753Smm	}
408228753Smm
409232153Smm	/* Note: The "warn" return is just to inform the options
410232153Smm	 * supervisor that we didn't handle it.  It will generate
411232153Smm	 * a suitable error if no one used this option. */
412228753Smm	return (ARCHIVE_WARN);
413228753Smm}
414228753Smm
415228753Smm/*
416228753Smm * Write data to the compressed stream.
417228753Smm */
418228753Smmstatic int
419231200Smmarchive_compressor_xz_write(struct archive_write_filter *f,
420231200Smm    const void *buff, size_t length)
421228753Smm{
422231200Smm	struct private_data *data = (struct private_data *)f->data;
423228753Smm	int ret;
424228753Smm
425228753Smm	/* Update statistics */
426231200Smm	data->total_in += length;
427248616Smm	if (f->code == ARCHIVE_FILTER_LZIP)
428231200Smm		data->crc32 = lzma_crc32(buff, length, data->crc32);
429228753Smm
430228753Smm	/* Compress input data to output buffer */
431231200Smm	data->stream.next_in = buff;
432231200Smm	data->stream.avail_in = length;
433231200Smm	if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK)
434228753Smm		return (ret);
435228753Smm
436228753Smm	return (ARCHIVE_OK);
437228753Smm}
438228753Smm
439228753Smm
440228753Smm/*
441228753Smm * Finish the compression...
442228753Smm */
443228753Smmstatic int
444231200Smmarchive_compressor_xz_close(struct archive_write_filter *f)
445228753Smm{
446231200Smm	struct private_data *data = (struct private_data *)f->data;
447358090Smm	int ret;
448228753Smm
449231200Smm	ret = drive_compressor(f, data, 1);
450231200Smm	if (ret == ARCHIVE_OK) {
451231200Smm		data->total_out +=
452231200Smm		    data->compressed_buffer_size - data->stream.avail_out;
453231200Smm		ret = __archive_write_filter(f->next_filter,
454231200Smm		    data->compressed,
455231200Smm		    data->compressed_buffer_size - data->stream.avail_out);
456248616Smm		if (f->code == ARCHIVE_FILTER_LZIP && ret == ARCHIVE_OK) {
457231200Smm			archive_le32enc(data->compressed, data->crc32);
458231200Smm			archive_le64enc(data->compressed+4, data->total_in);
459231200Smm			archive_le64enc(data->compressed+12, data->total_out + 20);
460231200Smm			ret = __archive_write_filter(f->next_filter,
461231200Smm			    data->compressed, 20);
462228753Smm		}
463228753Smm	}
464231200Smm	lzma_end(&(data->stream));
465358090Smm	return ret;
466228753Smm}
467228753Smm
468231200Smmstatic int
469231200Smmarchive_compressor_xz_free(struct archive_write_filter *f)
470231200Smm{
471231200Smm	struct private_data *data = (struct private_data *)f->data;
472231200Smm	free(data->compressed);
473231200Smm	free(data);
474231200Smm	f->data = NULL;
475231200Smm	return (ARCHIVE_OK);
476231200Smm}
477231200Smm
478228753Smm/*
479228753Smm * Utility function to push input data through compressor,
480228753Smm * writing full output blocks as necessary.
481228753Smm *
482228753Smm * Note that this handles both the regular write case (finishing ==
483228753Smm * false) and the end-of-archive case (finishing == true).
484228753Smm */
485228753Smmstatic int
486231200Smmdrive_compressor(struct archive_write_filter *f,
487231200Smm    struct private_data *data, int finishing)
488228753Smm{
489228753Smm	int ret;
490228753Smm
491228753Smm	for (;;) {
492231200Smm		if (data->stream.avail_out == 0) {
493231200Smm			data->total_out += data->compressed_buffer_size;
494231200Smm			ret = __archive_write_filter(f->next_filter,
495231200Smm			    data->compressed,
496231200Smm			    data->compressed_buffer_size);
497231200Smm			if (ret != ARCHIVE_OK)
498228753Smm				return (ARCHIVE_FATAL);
499231200Smm			data->stream.next_out = data->compressed;
500231200Smm			data->stream.avail_out = data->compressed_buffer_size;
501228753Smm		}
502228753Smm
503228753Smm		/* If there's nothing to do, we're done. */
504231200Smm		if (!finishing && data->stream.avail_in == 0)
505228753Smm			return (ARCHIVE_OK);
506228753Smm
507231200Smm		ret = lzma_code(&(data->stream),
508228753Smm		    finishing ? LZMA_FINISH : LZMA_RUN );
509228753Smm
510228753Smm		switch (ret) {
511228753Smm		case LZMA_OK:
512228753Smm			/* In non-finishing case, check if compressor
513228753Smm			 * consumed everything */
514231200Smm			if (!finishing && data->stream.avail_in == 0)
515228753Smm				return (ARCHIVE_OK);
516228753Smm			/* In finishing case, this return always means
517228753Smm			 * there's more work */
518228753Smm			break;
519228753Smm		case LZMA_STREAM_END:
520228753Smm			/* This return can only occur in finishing case. */
521228753Smm			if (finishing)
522228753Smm				return (ARCHIVE_OK);
523231200Smm			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
524228753Smm			    "lzma compression data error");
525228753Smm			return (ARCHIVE_FATAL);
526228753Smm		case LZMA_MEMLIMIT_ERROR:
527231200Smm			archive_set_error(f->archive, ENOMEM,
528228753Smm			    "lzma compression error: "
529228753Smm			    "%ju MiB would have been needed",
530231200Smm			    (uintmax_t)((lzma_memusage(&(data->stream))
531231200Smm				    + 1024 * 1024 -1)
532228753Smm				/ (1024 * 1024)));
533228753Smm			return (ARCHIVE_FATAL);
534228753Smm		default:
535228753Smm			/* Any other return value indicates an error. */
536231200Smm			archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
537228753Smm			    "lzma compression failed:"
538228753Smm			    " lzma_code() call returned status %d",
539228753Smm			    ret);
540228753Smm			return (ARCHIVE_FATAL);
541228753Smm		}
542228753Smm	}
543228753Smm}
544228753Smm
545228753Smm#endif /* HAVE_LZMA_H */
546